1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2018 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include <amount.h>
7 #include <chain.h>
8 #include <consensus/validation.h>
9 #include <core_io.h>
10 #include <httpserver.h>
11 #include <init.h>
12 #include <interfaces/chain.h>
13 #include <validation.h>
14 #include <key_io.h>
15 #include <net.h>
16 #include <node/transaction.h>
17 #include <outputtype.h>
18 #include <policy/feerate.h>
19 #include <policy/fees.h>
20 #include <policy/policy.h>
21 #include <policy/rbf.h>
22 #include <rpc/mining.h>
23 #include <rpc/rawtransaction.h>
24 #include <rpc/server.h>
25 #include <rpc/util.h>
26 #include <script/descriptor.h>
27 #include <script/sign.h>
28 #include <shutdown.h>
29 #include <timedata.h>
30 #include <util/bip32.h>
31 #include <util/system.h>
32 #include <util/moneystr.h>
33 #include <wallet/coincontrol.h>
34 #include <wallet/feebumper.h>
35 #include <wallet/psbtwallet.h>
36 #include <wallet/rpcwallet.h>
37 #include <wallet/wallet.h>
38 #include <wallet/walletdb.h>
39 #include <wallet/walletutil.h>
40 
41 #include <stdint.h>
42 
43 #include <univalue.h>
44 
45 #include <functional>
46 
47 static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
48 
GetWalletNameFromJSONRPCRequest(const JSONRPCRequest & request,std::string & wallet_name)49 bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name)
50 {
51     if (request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
52         // wallet endpoint was used
53         wallet_name = urlDecode(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
54         return true;
55     }
56     return false;
57 }
58 
GetWalletForJSONRPCRequest(const JSONRPCRequest & request)59 std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
60 {
61     std::string wallet_name;
62     if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
63         std::shared_ptr<CWallet> pwallet = GetWallet(wallet_name);
64         if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
65         return pwallet;
66     }
67 
68     std::vector<std::shared_ptr<CWallet>> wallets = GetWallets();
69     return wallets.size() == 1 || (request.fHelp && wallets.size() > 0) ? wallets[0] : nullptr;
70 }
71 
HelpRequiringPassphrase(CWallet * const pwallet)72 std::string HelpRequiringPassphrase(CWallet * const pwallet)
73 {
74     return pwallet && pwallet->IsCrypted()
75         ? "\nRequires wallet passphrase to be set with walletpassphrase call."
76         : "";
77 }
78 
EnsureWalletIsAvailable(CWallet * const pwallet,bool avoidException)79 bool EnsureWalletIsAvailable(CWallet * const pwallet, bool avoidException)
80 {
81     if (pwallet) return true;
82     if (avoidException) return false;
83     if (!HasWallets()) {
84         throw JSONRPCError(
85             RPC_METHOD_NOT_FOUND, "Method not found (wallet method is disabled because no wallet is loaded)");
86     }
87     throw JSONRPCError(RPC_WALLET_NOT_SPECIFIED,
88         "Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path).");
89 }
90 
EnsureWalletIsUnlocked(CWallet * const pwallet)91 void EnsureWalletIsUnlocked(CWallet * const pwallet)
92 {
93     if (pwallet->IsLocked()) {
94         throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
95     }
96 }
97 
WalletTxToJSON(interfaces::Chain & chain,interfaces::Chain::Lock & locked_chain,const CWalletTx & wtx,UniValue & entry)98 static void WalletTxToJSON(interfaces::Chain& chain, interfaces::Chain::Lock& locked_chain, const CWalletTx& wtx, UniValue& entry)
99 {
100     int confirms = wtx.GetDepthInMainChain(locked_chain);
101     entry.pushKV("confirmations", confirms);
102     if (wtx.IsCoinBase())
103         entry.pushKV("generated", true);
104     if (confirms > 0)
105     {
106         entry.pushKV("blockhash", wtx.hashBlock.GetHex());
107         entry.pushKV("blockindex", wtx.nIndex);
108         int64_t block_time;
109         bool found_block = chain.findBlock(wtx.hashBlock, nullptr /* block */, &block_time);
110         assert(found_block);
111         entry.pushKV("blocktime", block_time);
112     } else {
113         entry.pushKV("trusted", wtx.IsTrusted(locked_chain));
114     }
115     uint256 hash = wtx.GetHash();
116     entry.pushKV("txid", hash.GetHex());
117     UniValue conflicts(UniValue::VARR);
118     for (const uint256& conflict : wtx.GetConflicts())
119         conflicts.push_back(conflict.GetHex());
120     entry.pushKV("walletconflicts", conflicts);
121     entry.pushKV("time", wtx.GetTxTime());
122     entry.pushKV("timereceived", (int64_t)wtx.nTimeReceived);
123 
124     // Add opt-in RBF status
125     std::string rbfStatus = "no";
126     if (confirms <= 0) {
127         LOCK(mempool.cs);
128         RBFTransactionState rbfState = IsRBFOptIn(*wtx.tx, mempool);
129         if (rbfState == RBFTransactionState::UNKNOWN)
130             rbfStatus = "unknown";
131         else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125)
132             rbfStatus = "yes";
133     }
134     entry.pushKV("bip125-replaceable", rbfStatus);
135 
136     for (const std::pair<const std::string, std::string>& item : wtx.mapValue)
137         entry.pushKV(item.first, item.second);
138 }
139 
LabelFromValue(const UniValue & value)140 static std::string LabelFromValue(const UniValue& value)
141 {
142     std::string label = value.get_str();
143     if (label == "*")
144         throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name");
145     return label;
146 }
147 
getnewaddress(const JSONRPCRequest & request)148 static UniValue getnewaddress(const JSONRPCRequest& request)
149 {
150     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
151     CWallet* const pwallet = wallet.get();
152 
153     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
154         return NullUniValue;
155     }
156 
157     if (request.fHelp || request.params.size() > 2)
158         throw std::runtime_error(
159             RPCHelpMan{"getnewaddress",
160                 "\nReturns a new Litecoin address for receiving payments.\n"
161                 "If 'label' is specified, it is added to the address book \n"
162                 "so payments received with the address will be associated with 'label'.\n",
163                 {
164                     {"label", RPCArg::Type::STR, /* default */ "\"\"", "The label name for the address to be linked to. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created if there is no label by the given name."},
165                     {"address_type", RPCArg::Type::STR, /* default */ "set by -addresstype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
166                 },
167                 RPCResult{
168             "\"address\"    (string) The new litecoin address\n"
169                 },
170                 RPCExamples{
171                     HelpExampleCli("getnewaddress", "")
172             + HelpExampleRpc("getnewaddress", "")
173                 },
174             }.ToString());
175 
176     LOCK(pwallet->cs_wallet);
177 
178     if (!pwallet->CanGetAddresses()) {
179         throw JSONRPCError(RPC_WALLET_ERROR, "Error: This wallet has no available keys");
180     }
181 
182     // Parse the label first so we don't generate a key if there's an error
183     std::string label;
184     if (!request.params[0].isNull())
185         label = LabelFromValue(request.params[0]);
186 
187     OutputType output_type = pwallet->m_default_address_type;
188     if (!request.params[1].isNull()) {
189         if (!ParseOutputType(request.params[1].get_str(), output_type)) {
190             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[1].get_str()));
191         }
192     }
193 
194     if (!pwallet->IsLocked()) {
195         pwallet->TopUpKeyPool();
196     }
197 
198     // Generate a new key that is added to wallet
199     CPubKey newKey;
200     if (!pwallet->GetKeyFromPool(newKey)) {
201         throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
202     }
203     pwallet->LearnRelatedScripts(newKey, output_type);
204     CTxDestination dest = GetDestinationForKey(newKey, output_type);
205 
206     pwallet->SetAddressBook(dest, label, "receive");
207 
208     return EncodeDestination(dest);
209 }
210 
getrawchangeaddress(const JSONRPCRequest & request)211 static UniValue getrawchangeaddress(const JSONRPCRequest& request)
212 {
213     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
214     CWallet* const pwallet = wallet.get();
215 
216     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
217         return NullUniValue;
218     }
219 
220     if (request.fHelp || request.params.size() > 1)
221         throw std::runtime_error(
222             RPCHelpMan{"getrawchangeaddress",
223                 "\nReturns a new Litecoin address, for receiving change.\n"
224                 "This is for use with raw transactions, NOT normal use.\n",
225                 {
226                     {"address_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
227                 },
228                 RPCResult{
229             "\"address\"    (string) The address\n"
230                 },
231                 RPCExamples{
232                     HelpExampleCli("getrawchangeaddress", "")
233             + HelpExampleRpc("getrawchangeaddress", "")
234                 },
235             }.ToString());
236 
237     LOCK(pwallet->cs_wallet);
238 
239     if (!pwallet->CanGetAddresses(true)) {
240         throw JSONRPCError(RPC_WALLET_ERROR, "Error: This wallet has no available keys");
241     }
242 
243     if (!pwallet->IsLocked()) {
244         pwallet->TopUpKeyPool();
245     }
246 
247     OutputType output_type = pwallet->m_default_change_type != OutputType::CHANGE_AUTO ? pwallet->m_default_change_type : pwallet->m_default_address_type;
248     if (!request.params[0].isNull()) {
249         if (!ParseOutputType(request.params[0].get_str(), output_type)) {
250             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[0].get_str()));
251         }
252     }
253 
254     CReserveKey reservekey(pwallet);
255     CPubKey vchPubKey;
256     if (!reservekey.GetReservedKey(vchPubKey, true))
257         throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
258 
259     reservekey.KeepKey();
260 
261     pwallet->LearnRelatedScripts(vchPubKey, output_type);
262     CTxDestination dest = GetDestinationForKey(vchPubKey, output_type);
263 
264     return EncodeDestination(dest);
265 }
266 
267 
setlabel(const JSONRPCRequest & request)268 static UniValue setlabel(const JSONRPCRequest& request)
269 {
270     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
271     CWallet* const pwallet = wallet.get();
272 
273     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
274         return NullUniValue;
275     }
276 
277     if (request.fHelp || request.params.size() != 2)
278         throw std::runtime_error(
279             RPCHelpMan{"setlabel",
280                 "\nSets the label associated with the given address.\n",
281                 {
282                     {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The litecoin address to be associated with a label."},
283                     {"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The label to assign to the address."},
284                 },
285                 RPCResults{},
286                 RPCExamples{
287                     HelpExampleCli("setlabel", "\"LEr4HnaefWYHbMGXcFp2Po1NPRUeIk8km2\" \"tabby\"")
288             + HelpExampleRpc("setlabel", "\"LEr4HnaefWYHbMGXcFp2Po1NPRUeIk8km2\", \"tabby\"")
289                 },
290             }.ToString());
291 
292     LOCK(pwallet->cs_wallet);
293 
294     CTxDestination dest = DecodeDestination(request.params[0].get_str());
295     if (!IsValidDestination(dest)) {
296         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Litecoin address");
297     }
298 
299     std::string label = LabelFromValue(request.params[1]);
300 
301     if (IsMine(*pwallet, dest)) {
302         pwallet->SetAddressBook(dest, label, "receive");
303     } else {
304         pwallet->SetAddressBook(dest, label, "send");
305     }
306 
307     return NullUniValue;
308 }
309 
310 
SendMoney(interfaces::Chain::Lock & locked_chain,CWallet * const pwallet,const CTxDestination & address,CAmount nValue,bool fSubtractFeeFromAmount,const CCoinControl & coin_control,mapValue_t mapValue)311 static CTransactionRef SendMoney(interfaces::Chain::Lock& locked_chain, CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, const CCoinControl& coin_control, mapValue_t mapValue)
312 {
313     CAmount curBalance = pwallet->GetBalance();
314 
315     // Check amount
316     if (nValue <= 0)
317         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
318 
319     if (nValue > curBalance)
320         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
321 
322     if (pwallet->GetBroadcastTransactions() && !g_connman) {
323         throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
324     }
325 
326     // Parse Bitcoin address
327     CScript scriptPubKey = GetScriptForDestination(address);
328 
329     // Create and send the transaction
330     CReserveKey reservekey(pwallet);
331     CAmount nFeeRequired;
332     std::string strError;
333     std::vector<CRecipient> vecSend;
334     int nChangePosRet = -1;
335     CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
336     vecSend.push_back(recipient);
337     CTransactionRef tx;
338     if (!pwallet->CreateTransaction(locked_chain, vecSend, tx, reservekey, nFeeRequired, nChangePosRet, strError, coin_control)) {
339         if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance)
340             strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired));
341         throw JSONRPCError(RPC_WALLET_ERROR, strError);
342     }
343     CValidationState state;
344     if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, reservekey, g_connman.get(), state)) {
345         strError = strprintf("Error: The transaction was rejected! Reason given: %s", FormatStateMessage(state));
346         throw JSONRPCError(RPC_WALLET_ERROR, strError);
347     }
348     return tx;
349 }
350 
sendtoaddress(const JSONRPCRequest & request)351 static UniValue sendtoaddress(const JSONRPCRequest& request)
352 {
353     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
354     CWallet* const pwallet = wallet.get();
355 
356     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
357         return NullUniValue;
358     }
359 
360     if (request.fHelp || request.params.size() < 2 || request.params.size() > 8)
361         throw std::runtime_error(
362             RPCHelpMan{"sendtoaddress",
363                 "\nSend an amount to a given address." +
364                     HelpRequiringPassphrase(pwallet) + "\n",
365                 {
366                     {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The litecoin address to send to."},
367                     {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The amount in " + CURRENCY_UNIT + " to send. eg 0.1"},
368                     {"comment", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment used to store what the transaction is for.\n"
369             "                             This is not part of the transaction, just kept in your wallet."},
370                     {"comment_to", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment to store the name of the person or organization\n"
371             "                             to which you're sending the transaction. This is not part of the \n"
372             "                             transaction, just kept in your wallet."},
373                     {"subtractfeefromamount", RPCArg::Type::BOOL, /* default */ "false", "The fee will be deducted from the amount being sent.\n"
374             "                             The recipient will receive less litecoins than you enter in the amount field."},
375                     {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
376                     {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks)"},
377                     {"estimate_mode", RPCArg::Type::STR, /* default */ "UNSET", "The fee estimate mode, must be one of:\n"
378             "       \"UNSET\"\n"
379             "       \"ECONOMICAL\"\n"
380             "       \"CONSERVATIVE\""},
381                 },
382                 RPCResult{
383             "\"txid\"                  (string) The transaction id.\n"
384                 },
385                 RPCExamples{
386                     HelpExampleCli("sendtoaddress", "\"LEr4HnaefWYHbMGXcFp2Po1NPRUeIk8km2\" 0.1")
387             + HelpExampleCli("sendtoaddress", "\"LEr4HnaefWYHbMGXcFp2Po1NPRUeIk8km2\" 0.1 \"donation\" \"seans outpost\"")
388             + HelpExampleCli("sendtoaddress", "\"LEr4HnaefWYHbMGXcFp2Po1NPRUeIk8km2\" 0.1 \"\" \"\" true")
389             + HelpExampleRpc("sendtoaddress", "\"LEr4HnaefWYHbMGXcFp2Po1NPRUeIk8km2\", 0.1, \"donation\", \"seans outpost\"")
390                 },
391             }.ToString());
392 
393     // Make sure the results are valid at least up to the most recent block
394     // the user could have gotten from another RPC command prior to now
395     pwallet->BlockUntilSyncedToCurrentChain();
396 
397     auto locked_chain = pwallet->chain().lock();
398     LOCK(pwallet->cs_wallet);
399 
400     CTxDestination dest = DecodeDestination(request.params[0].get_str());
401     if (!IsValidDestination(dest)) {
402         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
403     }
404 
405     // Amount
406     CAmount nAmount = AmountFromValue(request.params[1]);
407     if (nAmount <= 0)
408         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
409 
410     // Wallet comments
411     mapValue_t mapValue;
412     if (!request.params[2].isNull() && !request.params[2].get_str().empty())
413         mapValue["comment"] = request.params[2].get_str();
414     if (!request.params[3].isNull() && !request.params[3].get_str().empty())
415         mapValue["to"] = request.params[3].get_str();
416 
417     bool fSubtractFeeFromAmount = false;
418     if (!request.params[4].isNull()) {
419         fSubtractFeeFromAmount = request.params[4].get_bool();
420     }
421 
422     CCoinControl coin_control;
423     if (!request.params[5].isNull()) {
424         coin_control.m_signal_bip125_rbf = request.params[5].get_bool();
425     }
426 
427     if (!request.params[6].isNull()) {
428         coin_control.m_confirm_target = ParseConfirmTarget(request.params[6]);
429     }
430 
431     if (!request.params[7].isNull()) {
432         if (!FeeModeFromString(request.params[7].get_str(), coin_control.m_fee_mode)) {
433             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
434         }
435     }
436 
437 
438     EnsureWalletIsUnlocked(pwallet);
439 
440     CTransactionRef tx = SendMoney(*locked_chain, pwallet, dest, nAmount, fSubtractFeeFromAmount, coin_control, std::move(mapValue));
441     return tx->GetHash().GetHex();
442 }
443 
listaddressgroupings(const JSONRPCRequest & request)444 static UniValue listaddressgroupings(const JSONRPCRequest& request)
445 {
446     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
447     CWallet* const pwallet = wallet.get();
448 
449     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
450         return NullUniValue;
451     }
452 
453     if (request.fHelp || request.params.size() != 0)
454         throw std::runtime_error(
455             RPCHelpMan{"listaddressgroupings",
456                 "\nLists groups of addresses which have had their common ownership\n"
457                 "made public by common use as inputs or as the resulting change\n"
458                 "in past transactions\n",
459                 {},
460                 RPCResult{
461             "[\n"
462             "  [\n"
463             "    [\n"
464             "      \"address\",            (string) The litecoin address\n"
465             "      amount,                 (numeric) The amount in " + CURRENCY_UNIT + "\n"
466             "      \"label\"               (string, optional) The label\n"
467             "    ]\n"
468             "    ,...\n"
469             "  ]\n"
470             "  ,...\n"
471             "]\n"
472                 },
473                 RPCExamples{
474                     HelpExampleCli("listaddressgroupings", "")
475             + HelpExampleRpc("listaddressgroupings", "")
476                 },
477             }.ToString());
478 
479     // Make sure the results are valid at least up to the most recent block
480     // the user could have gotten from another RPC command prior to now
481     pwallet->BlockUntilSyncedToCurrentChain();
482 
483     auto locked_chain = pwallet->chain().lock();
484     LOCK(pwallet->cs_wallet);
485 
486     UniValue jsonGroupings(UniValue::VARR);
487     std::map<CTxDestination, CAmount> balances = pwallet->GetAddressBalances(*locked_chain);
488     for (const std::set<CTxDestination>& grouping : pwallet->GetAddressGroupings()) {
489         UniValue jsonGrouping(UniValue::VARR);
490         for (const CTxDestination& address : grouping)
491         {
492             UniValue addressInfo(UniValue::VARR);
493             addressInfo.push_back(EncodeDestination(address));
494             addressInfo.push_back(ValueFromAmount(balances[address]));
495             {
496                 if (pwallet->mapAddressBook.find(address) != pwallet->mapAddressBook.end()) {
497                     addressInfo.push_back(pwallet->mapAddressBook.find(address)->second.name);
498                 }
499             }
500             jsonGrouping.push_back(addressInfo);
501         }
502         jsonGroupings.push_back(jsonGrouping);
503     }
504     return jsonGroupings;
505 }
506 
signmessage(const JSONRPCRequest & request)507 static UniValue signmessage(const JSONRPCRequest& request)
508 {
509     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
510     CWallet* const pwallet = wallet.get();
511 
512     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
513         return NullUniValue;
514     }
515 
516     if (request.fHelp || request.params.size() != 2)
517         throw std::runtime_error(
518             RPCHelpMan{"signmessage",
519                 "\nSign a message with the private key of an address" +
520                     HelpRequiringPassphrase(pwallet) + "\n",
521                 {
522                     {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The litecoin address to use for the private key."},
523                     {"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message to create a signature of."},
524                 },
525                 RPCResult{
526             "\"signature\"          (string) The signature of the message encoded in base 64\n"
527                 },
528                 RPCExamples{
529             "\nUnlock the wallet for 30 seconds\n"
530             + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
531             "\nCreate the signature\n"
532             + HelpExampleCli("signmessage", "\"LEr4hNAefWYhBMgxCFP2Po1NPrUeiK8kM2\" \"my message\"") +
533             "\nVerify the signature\n"
534             + HelpExampleCli("verifymessage", "\"LEr4hNAefWYhBMgxCFP2Po1NPrUeiK8kM2\" \"signature\" \"my message\"") +
535             "\nAs a JSON-RPC call\n"
536             + HelpExampleRpc("signmessage", "\"LEr4hNAefWYhBMgxCFP2Po1NPrUeiK8kM2\", \"my message\"")
537                 },
538             }.ToString());
539 
540     auto locked_chain = pwallet->chain().lock();
541     LOCK(pwallet->cs_wallet);
542 
543     EnsureWalletIsUnlocked(pwallet);
544 
545     std::string strAddress = request.params[0].get_str();
546     std::string strMessage = request.params[1].get_str();
547 
548     CTxDestination dest = DecodeDestination(strAddress);
549     if (!IsValidDestination(dest)) {
550         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
551     }
552 
553     const CKeyID *keyID = boost::get<CKeyID>(&dest);
554     if (!keyID) {
555         throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
556     }
557 
558     CKey key;
559     if (!pwallet->GetKey(*keyID, key)) {
560         throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
561     }
562 
563     CHashWriter ss(SER_GETHASH, 0);
564     ss << strMessageMagic;
565     ss << strMessage;
566 
567     std::vector<unsigned char> vchSig;
568     if (!key.SignCompact(ss.GetHash(), vchSig))
569         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
570 
571     return EncodeBase64(vchSig.data(), vchSig.size());
572 }
573 
getreceivedbyaddress(const JSONRPCRequest & request)574 static UniValue getreceivedbyaddress(const JSONRPCRequest& request)
575 {
576     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
577     CWallet* const pwallet = wallet.get();
578 
579     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
580         return NullUniValue;
581     }
582 
583     if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
584         throw std::runtime_error(
585             RPCHelpMan{"getreceivedbyaddress",
586                 "\nReturns the total amount received by the given address in transactions with at least minconf confirmations.\n",
587                 {
588                     {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The litecoin address for transactions."},
589                     {"minconf", RPCArg::Type::NUM, /* default */ "1", "Only include transactions confirmed at least this many times."},
590                 },
591                 RPCResult{
592             "amount   (numeric) The total amount in " + CURRENCY_UNIT + " received at this address.\n"
593                 },
594                 RPCExamples{
595             "\nThe amount from transactions with at least 1 confirmation\n"
596             + HelpExampleCli("getreceivedbyaddress", "\"LEr4hNAefWYhBMgxCFP2Po1NPrUeiK8kM2\"") +
597             "\nThe amount including unconfirmed transactions, zero confirmations\n"
598             + HelpExampleCli("getreceivedbyaddress", "\"LEr4hNAefWYhBMgxCFP2Po1NPrUeiK8kM2\" 0") +
599             "\nThe amount with at least 6 confirmations\n"
600             + HelpExampleCli("getreceivedbyaddress", "\"LEr4hNAefWYhBMgxCFP2Po1NPrUeiK8kM2\" 6") +
601             "\nAs a JSON-RPC call\n"
602             + HelpExampleRpc("getreceivedbyaddress", "\"LEr4hNAefWYhBMgxCFP2Po1NPrUeiK8kM2\", 6")
603                 },
604             }.ToString());
605 
606     // Make sure the results are valid at least up to the most recent block
607     // the user could have gotten from another RPC command prior to now
608     pwallet->BlockUntilSyncedToCurrentChain();
609 
610     LockAnnotation lock(::cs_main); // Temporary, for CheckFinalTx below. Removed in upcoming commit.
611     auto locked_chain = pwallet->chain().lock();
612     LOCK(pwallet->cs_wallet);
613 
614     // Bitcoin address
615     CTxDestination dest = DecodeDestination(request.params[0].get_str());
616     if (!IsValidDestination(dest)) {
617         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Litecoin address");
618     }
619     CScript scriptPubKey = GetScriptForDestination(dest);
620     if (!IsMine(*pwallet, scriptPubKey)) {
621         throw JSONRPCError(RPC_WALLET_ERROR, "Address not found in wallet");
622     }
623 
624     // Minimum confirmations
625     int nMinDepth = 1;
626     if (!request.params[1].isNull())
627         nMinDepth = request.params[1].get_int();
628 
629     // Tally
630     CAmount nAmount = 0;
631     for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
632         const CWalletTx& wtx = pairWtx.second;
633         if (wtx.IsCoinBase() || !CheckFinalTx(*wtx.tx))
634             continue;
635 
636         for (const CTxOut& txout : wtx.tx->vout)
637             if (txout.scriptPubKey == scriptPubKey)
638                 if (wtx.GetDepthInMainChain(*locked_chain) >= nMinDepth)
639                     nAmount += txout.nValue;
640     }
641 
642     return  ValueFromAmount(nAmount);
643 }
644 
645 
getreceivedbylabel(const JSONRPCRequest & request)646 static UniValue getreceivedbylabel(const JSONRPCRequest& request)
647 {
648     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
649     CWallet* const pwallet = wallet.get();
650 
651     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
652         return NullUniValue;
653     }
654 
655     if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
656         throw std::runtime_error(
657             RPCHelpMan{"getreceivedbylabel",
658                 "\nReturns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.\n",
659                 {
660                     {"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The selected label, may be the default label using \"\"."},
661                     {"minconf", RPCArg::Type::NUM, /* default */ "1", "Only include transactions confirmed at least this many times."},
662                 },
663                 RPCResult{
664             "amount              (numeric) The total amount in " + CURRENCY_UNIT + " received for this label.\n"
665                 },
666                 RPCExamples{
667             "\nAmount received by the default label with at least 1 confirmation\n"
668             + HelpExampleCli("getreceivedbylabel", "\"\"") +
669             "\nAmount received at the tabby label including unconfirmed amounts with zero confirmations\n"
670             + HelpExampleCli("getreceivedbylabel", "\"tabby\" 0") +
671             "\nThe amount with at least 6 confirmations\n"
672             + HelpExampleCli("getreceivedbylabel", "\"tabby\" 6") +
673             "\nAs a JSON-RPC call\n"
674             + HelpExampleRpc("getreceivedbylabel", "\"tabby\", 6")
675                 },
676             }.ToString());
677 
678     // Make sure the results are valid at least up to the most recent block
679     // the user could have gotten from another RPC command prior to now
680     pwallet->BlockUntilSyncedToCurrentChain();
681 
682     LockAnnotation lock(::cs_main); // Temporary, for CheckFinalTx below. Removed in upcoming commit.
683     auto locked_chain = pwallet->chain().lock();
684     LOCK(pwallet->cs_wallet);
685 
686     // Minimum confirmations
687     int nMinDepth = 1;
688     if (!request.params[1].isNull())
689         nMinDepth = request.params[1].get_int();
690 
691     // Get the set of pub keys assigned to label
692     std::string label = LabelFromValue(request.params[0]);
693     std::set<CTxDestination> setAddress = pwallet->GetLabelAddresses(label);
694 
695     // Tally
696     CAmount nAmount = 0;
697     for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
698         const CWalletTx& wtx = pairWtx.second;
699         if (wtx.IsCoinBase() || !CheckFinalTx(*wtx.tx))
700             continue;
701 
702         for (const CTxOut& txout : wtx.tx->vout)
703         {
704             CTxDestination address;
705             if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwallet, address) && setAddress.count(address)) {
706                 if (wtx.GetDepthInMainChain(*locked_chain) >= nMinDepth)
707                     nAmount += txout.nValue;
708             }
709         }
710     }
711 
712     return ValueFromAmount(nAmount);
713 }
714 
715 
getbalance(const JSONRPCRequest & request)716 static UniValue getbalance(const JSONRPCRequest& request)
717 {
718     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
719     CWallet* const pwallet = wallet.get();
720 
721     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
722         return NullUniValue;
723     }
724 
725     if (request.fHelp || (request.params.size() > 3 ))
726         throw std::runtime_error(
727             RPCHelpMan{"getbalance",
728                 "\nReturns the total available balance.\n"
729                 "The available balance is what the wallet considers currently spendable, and is\n"
730                 "thus affected by options which limit spendability such as -spendzeroconfchange.\n",
731                 {
732                     {"dummy", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Remains for backward compatibility. Must be excluded or set to \"*\"."},
733                     {"minconf", RPCArg::Type::NUM, /* default */ "0", "Only include transactions confirmed at least this many times."},
734                     {"include_watchonly", RPCArg::Type::BOOL, /* default */ "false", "Also include balance in watch-only addresses (see 'importaddress')"},
735                 },
736                 RPCResult{
737             "amount              (numeric) The total amount in " + CURRENCY_UNIT + " received for this wallet.\n"
738                 },
739                 RPCExamples{
740             "\nThe total amount in the wallet with 1 or more confirmations\n"
741             + HelpExampleCli("getbalance", "") +
742             "\nThe total amount in the wallet at least 6 blocks confirmed\n"
743             + HelpExampleCli("getbalance", "\"*\" 6") +
744             "\nAs a JSON-RPC call\n"
745             + HelpExampleRpc("getbalance", "\"*\", 6")
746                 },
747             }.ToString());
748 
749     // Make sure the results are valid at least up to the most recent block
750     // the user could have gotten from another RPC command prior to now
751     pwallet->BlockUntilSyncedToCurrentChain();
752 
753     auto locked_chain = pwallet->chain().lock();
754     LOCK(pwallet->cs_wallet);
755 
756     const UniValue& dummy_value = request.params[0];
757     if (!dummy_value.isNull() && dummy_value.get_str() != "*") {
758         throw JSONRPCError(RPC_METHOD_DEPRECATED, "dummy first argument must be excluded or set to \"*\".");
759     }
760 
761     int min_depth = 0;
762     if (!request.params[1].isNull()) {
763         min_depth = request.params[1].get_int();
764     }
765 
766     isminefilter filter = ISMINE_SPENDABLE;
767     if (!request.params[2].isNull() && request.params[2].get_bool()) {
768         filter = filter | ISMINE_WATCH_ONLY;
769     }
770 
771     return ValueFromAmount(pwallet->GetBalance(filter, min_depth));
772 }
773 
getunconfirmedbalance(const JSONRPCRequest & request)774 static UniValue getunconfirmedbalance(const JSONRPCRequest &request)
775 {
776     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
777     CWallet* const pwallet = wallet.get();
778 
779     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
780         return NullUniValue;
781     }
782 
783     if (request.fHelp || request.params.size() > 0)
784         throw std::runtime_error(
785             RPCHelpMan{"getunconfirmedbalance",
786                 "Returns the server's total unconfirmed balance\n",
787                 {},
788                 RPCResults{},
789                 RPCExamples{""},
790             }.ToString());
791 
792     // Make sure the results are valid at least up to the most recent block
793     // the user could have gotten from another RPC command prior to now
794     pwallet->BlockUntilSyncedToCurrentChain();
795 
796     auto locked_chain = pwallet->chain().lock();
797     LOCK(pwallet->cs_wallet);
798 
799     return ValueFromAmount(pwallet->GetUnconfirmedBalance());
800 }
801 
802 
sendmany(const JSONRPCRequest & request)803 static UniValue sendmany(const JSONRPCRequest& request)
804 {
805     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
806     CWallet* const pwallet = wallet.get();
807 
808     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
809         return NullUniValue;
810     }
811 
812     if (request.fHelp || request.params.size() < 2 || request.params.size() > 8)
813         throw std::runtime_error(
814             RPCHelpMan{"sendmany",
815                 "\nSend multiple times. Amounts are double-precision floating point numbers." +
816                     HelpRequiringPassphrase(pwallet) + "\n",
817                 {
818                     {"dummy", RPCArg::Type::STR, RPCArg::Optional::NO, "Must be set to \"\" for backwards compatibility.", "\"\""},
819                     {"amounts", RPCArg::Type::OBJ, RPCArg::Optional::NO, "A json object with addresses and amounts",
820                         {
821                             {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The litecoin address is the key, the numeric amount (can be string) in " + CURRENCY_UNIT + " is the value"},
822                         },
823                     },
824                     {"minconf", RPCArg::Type::NUM, /* default */ "1", "Only use the balance confirmed at least this many times."},
825                     {"comment", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment"},
826                     {"subtractfeefrom", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "A json array with addresses.\n"
827             "                           The fee will be equally deducted from the amount of each selected address.\n"
828             "                           Those recipients will receive less litecoins than you enter in their corresponding amount field.\n"
829             "                           If no addresses are specified here, the sender pays the fee.",
830                         {
831                             {"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Subtract fee from this address"},
832                         },
833                     },
834                     {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
835                     {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks)"},
836                     {"estimate_mode", RPCArg::Type::STR, /* default */ "UNSET", "The fee estimate mode, must be one of:\n"
837             "       \"UNSET\"\n"
838             "       \"ECONOMICAL\"\n"
839             "       \"CONSERVATIVE\""},
840                 },
841                  RPCResult{
842             "\"txid\"                   (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
843             "                                    the number of addresses.\n"
844                  },
845                 RPCExamples{
846             "\nSend two amounts to two different addresses:\n"
847             + HelpExampleCli("sendmany", "\"\" \"{\\\"LEr4hNAefWYhBMgxCFP2Po1NPrUeiK8kM2\\\":0.01,\\\"LbhhnrHHVFP1eUjP1tdNIYeEVsNHfN9FCw\\\":0.02}\"") +
848             "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
849             + HelpExampleCli("sendmany", "\"\" \"{\\\"LEr4hNAefWYhBMgxCFP2Po1NPrUeiK8kM2\\\":0.01,\\\"LbhhnrHHVFP1eUjP1tdNIYeEVsNHfN9FCw\\\":0.02}\" 6 \"testing\"") +
850             "\nSend two amounts to two different addresses, subtract fee from amount:\n"
851             + HelpExampleCli("sendmany", "\"\" \"{\\\"LEr4hNAefWYhBMgxCFP2Po1NPrUeiK8kM2\\\":0.01,\\\"LbhhnrHHVFP1eUjP1tdNIYeEVsNHfN9FCw\\\":0.02}\" 1 \"\" \"[\\\"LEr4hNAefWYhBMgxCFP2Po1NPrUeiK8kM2\\\",\\\"LbhhnrHHVFP1eUjP1tdNIYeEVsNHfN9FCw\\\"]\"") +
852             "\nAs a JSON-RPC call\n"
853             + HelpExampleRpc("sendmany", "\"\", {\"LEr4hNAefWYhBMgxCFP2Po1NPrUeiK8kM2\":0.01,\"LbhhnrHHVFP1eUjP1tdNIYeEVsNHfN9FCw\":0.02}, 6, \"testing\"")
854                 },
855             }.ToString());
856 
857     // Make sure the results are valid at least up to the most recent block
858     // the user could have gotten from another RPC command prior to now
859     pwallet->BlockUntilSyncedToCurrentChain();
860 
861     auto locked_chain = pwallet->chain().lock();
862     LOCK(pwallet->cs_wallet);
863 
864     if (pwallet->GetBroadcastTransactions() && !g_connman) {
865         throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
866     }
867 
868     if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
869         throw JSONRPCError(RPC_INVALID_PARAMETER, "Dummy value must be set to \"\"");
870     }
871     UniValue sendTo = request.params[1].get_obj();
872     int nMinDepth = 1;
873     if (!request.params[2].isNull())
874         nMinDepth = request.params[2].get_int();
875 
876     mapValue_t mapValue;
877     if (!request.params[3].isNull() && !request.params[3].get_str().empty())
878         mapValue["comment"] = request.params[3].get_str();
879 
880     UniValue subtractFeeFromAmount(UniValue::VARR);
881     if (!request.params[4].isNull())
882         subtractFeeFromAmount = request.params[4].get_array();
883 
884     CCoinControl coin_control;
885     if (!request.params[5].isNull()) {
886         coin_control.m_signal_bip125_rbf = request.params[5].get_bool();
887     }
888 
889     if (!request.params[6].isNull()) {
890         coin_control.m_confirm_target = ParseConfirmTarget(request.params[6]);
891     }
892 
893     if (!request.params[7].isNull()) {
894         if (!FeeModeFromString(request.params[7].get_str(), coin_control.m_fee_mode)) {
895             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
896         }
897     }
898 
899     std::set<CTxDestination> destinations;
900     std::vector<CRecipient> vecSend;
901 
902     CAmount totalAmount = 0;
903     std::vector<std::string> keys = sendTo.getKeys();
904     for (const std::string& name_ : keys) {
905         CTxDestination dest = DecodeDestination(name_);
906         if (!IsValidDestination(dest)) {
907             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Litecoin address: ") + name_);
908         }
909 
910         if (destinations.count(dest)) {
911             throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
912         }
913         destinations.insert(dest);
914 
915         CScript scriptPubKey = GetScriptForDestination(dest);
916         CAmount nAmount = AmountFromValue(sendTo[name_]);
917         if (nAmount <= 0)
918             throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
919         totalAmount += nAmount;
920 
921         bool fSubtractFeeFromAmount = false;
922         for (unsigned int idx = 0; idx < subtractFeeFromAmount.size(); idx++) {
923             const UniValue& addr = subtractFeeFromAmount[idx];
924             if (addr.get_str() == name_)
925                 fSubtractFeeFromAmount = true;
926         }
927 
928         CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
929         vecSend.push_back(recipient);
930     }
931 
932     EnsureWalletIsUnlocked(pwallet);
933 
934     // Check funds
935     if (totalAmount > pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth)) {
936         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Wallet has insufficient funds");
937     }
938 
939     // Shuffle recipient list
940     std::shuffle(vecSend.begin(), vecSend.end(), FastRandomContext());
941 
942     // Send
943     CReserveKey keyChange(pwallet);
944     CAmount nFeeRequired = 0;
945     int nChangePosRet = -1;
946     std::string strFailReason;
947     CTransactionRef tx;
948     bool fCreated = pwallet->CreateTransaction(*locked_chain, vecSend, tx, keyChange, nFeeRequired, nChangePosRet, strFailReason, coin_control);
949     if (!fCreated)
950         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
951     CValidationState state;
952     if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, keyChange, g_connman.get(), state)) {
953         strFailReason = strprintf("Transaction commit failed:: %s", FormatStateMessage(state));
954         throw JSONRPCError(RPC_WALLET_ERROR, strFailReason);
955     }
956 
957     return tx->GetHash().GetHex();
958 }
959 
addmultisigaddress(const JSONRPCRequest & request)960 static UniValue addmultisigaddress(const JSONRPCRequest& request)
961 {
962     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
963     CWallet* const pwallet = wallet.get();
964 
965     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
966         return NullUniValue;
967     }
968 
969     if (request.fHelp || request.params.size() < 2 || request.params.size() > 4) {
970         std::string msg =
971             RPCHelpMan{"addmultisigaddress",
972                 "\nAdd a nrequired-to-sign multisignature address to the wallet. Requires a new wallet backup.\n"
973                 "Each key is a Litecoin address or hex-encoded public key.\n"
974                 "This functionality is only intended for use with non-watchonly addresses.\n"
975                 "See `importaddress` for watchonly p2sh address support.\n"
976                 "If 'label' is specified, assign address to that label.\n",
977                 {
978                     {"nrequired", RPCArg::Type::NUM, RPCArg::Optional::NO, "The number of required signatures out of the n keys or addresses."},
979                     {"keys", RPCArg::Type::ARR, RPCArg::Optional::NO, "A json array of litecoin addresses or hex-encoded public keys",
980                         {
981                             {"key", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "litecoin address or hex-encoded public key"},
982                         },
983                         },
984                     {"label", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A label to assign the addresses to."},
985                     {"address_type", RPCArg::Type::STR, /* default */ "set by -addresstype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
986                 },
987                 RPCResult{
988             "{\n"
989             "  \"address\":\"multisigaddress\",    (string) The value of the new multisig address.\n"
990             "  \"redeemScript\":\"script\"         (string) The string value of the hex-encoded redemption script.\n"
991             "}\n"
992                 },
993                 RPCExamples{
994             "\nAdd a multisig address from 2 addresses\n"
995             + HelpExampleCli("addmultisigaddress", "2 \"[\\\"LEr4hnAefwYhBmGxcFP2Po1NPrUEIk8KM2\\\",\\\"LYKr1oaPSqShthukmLDhdZsqUJgzVnQiAQ\\\"]\"") +
996             "\nAs a JSON-RPC call\n"
997             + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"LEr4hnAefwYhBmGxcFP2Po1NPrUEIk8KM2\\\",\\\"LYKr1oaPSqShthukmLDhdZsqUJgzVnQiAQ\\\"]\"")
998                 },
999             }.ToString();
1000         throw std::runtime_error(msg);
1001     }
1002 
1003     auto locked_chain = pwallet->chain().lock();
1004     LOCK(pwallet->cs_wallet);
1005 
1006     std::string label;
1007     if (!request.params[2].isNull())
1008         label = LabelFromValue(request.params[2]);
1009 
1010     int required = request.params[0].get_int();
1011 
1012     // Get the public keys
1013     const UniValue& keys_or_addrs = request.params[1].get_array();
1014     std::vector<CPubKey> pubkeys;
1015     for (unsigned int i = 0; i < keys_or_addrs.size(); ++i) {
1016         if (IsHex(keys_or_addrs[i].get_str()) && (keys_or_addrs[i].get_str().length() == 66 || keys_or_addrs[i].get_str().length() == 130)) {
1017             pubkeys.push_back(HexToPubKey(keys_or_addrs[i].get_str()));
1018         } else {
1019             pubkeys.push_back(AddrToPubKey(pwallet, keys_or_addrs[i].get_str()));
1020         }
1021     }
1022 
1023     OutputType output_type = pwallet->m_default_address_type;
1024     if (!request.params[3].isNull()) {
1025         if (!ParseOutputType(request.params[3].get_str(), output_type)) {
1026             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[3].get_str()));
1027         }
1028     }
1029 
1030     // Construct using pay-to-script-hash:
1031     CScript inner;
1032     CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, *pwallet, inner);
1033     pwallet->SetAddressBook(dest, label, "send");
1034 
1035     UniValue result(UniValue::VOBJ);
1036     result.pushKV("address", EncodeDestination(dest));
1037     result.pushKV("redeemScript", HexStr(inner.begin(), inner.end()));
1038     return result;
1039 }
1040 
1041 struct tallyitem
1042 {
1043     CAmount nAmount{0};
1044     int nConf{std::numeric_limits<int>::max()};
1045     std::vector<uint256> txids;
1046     bool fIsWatchonly{false};
tallyitemtallyitem1047     tallyitem()
1048     {
1049     }
1050 };
1051 
ListReceived(interfaces::Chain::Lock & locked_chain,CWallet * const pwallet,const UniValue & params,bool by_label)1052 static UniValue ListReceived(interfaces::Chain::Lock& locked_chain, CWallet * const pwallet, const UniValue& params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
1053 {
1054     LockAnnotation lock(::cs_main); // Temporary, for CheckFinalTx below. Removed in upcoming commit.
1055 
1056     // Minimum confirmations
1057     int nMinDepth = 1;
1058     if (!params[0].isNull())
1059         nMinDepth = params[0].get_int();
1060 
1061     // Whether to include empty labels
1062     bool fIncludeEmpty = false;
1063     if (!params[1].isNull())
1064         fIncludeEmpty = params[1].get_bool();
1065 
1066     isminefilter filter = ISMINE_SPENDABLE;
1067     if(!params[2].isNull())
1068         if(params[2].get_bool())
1069             filter = filter | ISMINE_WATCH_ONLY;
1070 
1071     bool has_filtered_address = false;
1072     CTxDestination filtered_address = CNoDestination();
1073     if (!by_label && params.size() > 3) {
1074         if (!IsValidDestinationString(params[3].get_str())) {
1075             throw JSONRPCError(RPC_WALLET_ERROR, "address_filter parameter was invalid");
1076         }
1077         filtered_address = DecodeDestination(params[3].get_str());
1078         has_filtered_address = true;
1079     }
1080 
1081     // Tally
1082     std::map<CTxDestination, tallyitem> mapTally;
1083     for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
1084         const CWalletTx& wtx = pairWtx.second;
1085 
1086         if (wtx.IsCoinBase() || !CheckFinalTx(*wtx.tx))
1087             continue;
1088 
1089         int nDepth = wtx.GetDepthInMainChain(locked_chain);
1090         if (nDepth < nMinDepth)
1091             continue;
1092 
1093         for (const CTxOut& txout : wtx.tx->vout)
1094         {
1095             CTxDestination address;
1096             if (!ExtractDestination(txout.scriptPubKey, address))
1097                 continue;
1098 
1099             if (has_filtered_address && !(filtered_address == address)) {
1100                 continue;
1101             }
1102 
1103             isminefilter mine = IsMine(*pwallet, address);
1104             if(!(mine & filter))
1105                 continue;
1106 
1107             tallyitem& item = mapTally[address];
1108             item.nAmount += txout.nValue;
1109             item.nConf = std::min(item.nConf, nDepth);
1110             item.txids.push_back(wtx.GetHash());
1111             if (mine & ISMINE_WATCH_ONLY)
1112                 item.fIsWatchonly = true;
1113         }
1114     }
1115 
1116     // Reply
1117     UniValue ret(UniValue::VARR);
1118     std::map<std::string, tallyitem> label_tally;
1119 
1120     // Create mapAddressBook iterator
1121     // If we aren't filtering, go from begin() to end()
1122     auto start = pwallet->mapAddressBook.begin();
1123     auto end = pwallet->mapAddressBook.end();
1124     // If we are filtering, find() the applicable entry
1125     if (has_filtered_address) {
1126         start = pwallet->mapAddressBook.find(filtered_address);
1127         if (start != end) {
1128             end = std::next(start);
1129         }
1130     }
1131 
1132     for (auto item_it = start; item_it != end; ++item_it)
1133     {
1134         const CTxDestination& address = item_it->first;
1135         const std::string& label = item_it->second.name;
1136         auto it = mapTally.find(address);
1137         if (it == mapTally.end() && !fIncludeEmpty)
1138             continue;
1139 
1140         CAmount nAmount = 0;
1141         int nConf = std::numeric_limits<int>::max();
1142         bool fIsWatchonly = false;
1143         if (it != mapTally.end())
1144         {
1145             nAmount = (*it).second.nAmount;
1146             nConf = (*it).second.nConf;
1147             fIsWatchonly = (*it).second.fIsWatchonly;
1148         }
1149 
1150         if (by_label)
1151         {
1152             tallyitem& _item = label_tally[label];
1153             _item.nAmount += nAmount;
1154             _item.nConf = std::min(_item.nConf, nConf);
1155             _item.fIsWatchonly = fIsWatchonly;
1156         }
1157         else
1158         {
1159             UniValue obj(UniValue::VOBJ);
1160             if(fIsWatchonly)
1161                 obj.pushKV("involvesWatchonly", true);
1162             obj.pushKV("address",       EncodeDestination(address));
1163             obj.pushKV("amount",        ValueFromAmount(nAmount));
1164             obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
1165             obj.pushKV("label", label);
1166             UniValue transactions(UniValue::VARR);
1167             if (it != mapTally.end())
1168             {
1169                 for (const uint256& _item : (*it).second.txids)
1170                 {
1171                     transactions.push_back(_item.GetHex());
1172                 }
1173             }
1174             obj.pushKV("txids", transactions);
1175             ret.push_back(obj);
1176         }
1177     }
1178 
1179     if (by_label)
1180     {
1181         for (const auto& entry : label_tally)
1182         {
1183             CAmount nAmount = entry.second.nAmount;
1184             int nConf = entry.second.nConf;
1185             UniValue obj(UniValue::VOBJ);
1186             if (entry.second.fIsWatchonly)
1187                 obj.pushKV("involvesWatchonly", true);
1188             obj.pushKV("amount",        ValueFromAmount(nAmount));
1189             obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
1190             obj.pushKV("label",         entry.first);
1191             ret.push_back(obj);
1192         }
1193     }
1194 
1195     return ret;
1196 }
1197 
listreceivedbyaddress(const JSONRPCRequest & request)1198 static UniValue listreceivedbyaddress(const JSONRPCRequest& request)
1199 {
1200     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1201     CWallet* const pwallet = wallet.get();
1202 
1203     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
1204         return NullUniValue;
1205     }
1206 
1207     if (request.fHelp || request.params.size() > 4)
1208         throw std::runtime_error(
1209             RPCHelpMan{"listreceivedbyaddress",
1210                 "\nList balances by receiving address.\n",
1211                 {
1212                     {"minconf", RPCArg::Type::NUM, /* default */ "1", "The minimum number of confirmations before payments are included."},
1213                     {"include_empty", RPCArg::Type::BOOL, /* default */ "false", "Whether to include addresses that haven't received any payments."},
1214                     {"include_watchonly", RPCArg::Type::BOOL, /* default */ "false", "Whether to include watch-only addresses (see 'importaddress')."},
1215                     {"address_filter", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If present, only return information on this address."},
1216                 },
1217                 RPCResult{
1218             "[\n"
1219             "  {\n"
1220             "    \"involvesWatchonly\" : true,        (bool) Only returned if imported addresses were involved in transaction\n"
1221             "    \"address\" : \"receivingaddress\",  (string) The receiving address\n"
1222             "    \"amount\" : x.xxx,                  (numeric) The total amount in " + CURRENCY_UNIT + " received by the address\n"
1223             "    \"confirmations\" : n,               (numeric) The number of confirmations of the most recent transaction included\n"
1224             "    \"label\" : \"label\",               (string) The label of the receiving address. The default label is \"\".\n"
1225             "    \"txids\": [\n"
1226             "       \"txid\",                         (string) The ids of transactions received with the address \n"
1227             "       ...\n"
1228             "    ]\n"
1229             "  }\n"
1230             "  ,...\n"
1231             "]\n"
1232                 },
1233                 RPCExamples{
1234                     HelpExampleCli("listreceivedbyaddress", "")
1235             + HelpExampleCli("listreceivedbyaddress", "6 true")
1236             + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
1237             + HelpExampleRpc("listreceivedbyaddress", "6, true, true, \"LEr4HnaefWYHbMGXcFp2Po1NPRUeIk8km2\"")
1238                 },
1239             }.ToString());
1240 
1241     // Make sure the results are valid at least up to the most recent block
1242     // the user could have gotten from another RPC command prior to now
1243     pwallet->BlockUntilSyncedToCurrentChain();
1244 
1245     auto locked_chain = pwallet->chain().lock();
1246     LOCK(pwallet->cs_wallet);
1247 
1248     return ListReceived(*locked_chain, pwallet, request.params, false);
1249 }
1250 
listreceivedbylabel(const JSONRPCRequest & request)1251 static UniValue listreceivedbylabel(const JSONRPCRequest& request)
1252 {
1253     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1254     CWallet* const pwallet = wallet.get();
1255 
1256     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
1257         return NullUniValue;
1258     }
1259 
1260     if (request.fHelp || request.params.size() > 3)
1261         throw std::runtime_error(
1262             RPCHelpMan{"listreceivedbylabel",
1263                 "\nList received transactions by label.\n",
1264                 {
1265                     {"minconf", RPCArg::Type::NUM, /* default */ "1", "The minimum number of confirmations before payments are included."},
1266                     {"include_empty", RPCArg::Type::BOOL, /* default */ "false", "Whether to include labels that haven't received any payments."},
1267                     {"include_watchonly", RPCArg::Type::BOOL, /* default */ "false", "Whether to include watch-only addresses (see 'importaddress')."},
1268                 },
1269                 RPCResult{
1270             "[\n"
1271             "  {\n"
1272             "    \"involvesWatchonly\" : true,   (bool) Only returned if imported addresses were involved in transaction\n"
1273             "    \"amount\" : x.xxx,             (numeric) The total amount received by addresses with this label\n"
1274             "    \"confirmations\" : n,          (numeric) The number of confirmations of the most recent transaction included\n"
1275             "    \"label\" : \"label\"           (string) The label of the receiving address. The default label is \"\".\n"
1276             "  }\n"
1277             "  ,...\n"
1278             "]\n"
1279                 },
1280                 RPCExamples{
1281                     HelpExampleCli("listreceivedbylabel", "")
1282             + HelpExampleCli("listreceivedbylabel", "6 true")
1283             + HelpExampleRpc("listreceivedbylabel", "6, true, true")
1284                 },
1285             }.ToString());
1286 
1287     // Make sure the results are valid at least up to the most recent block
1288     // the user could have gotten from another RPC command prior to now
1289     pwallet->BlockUntilSyncedToCurrentChain();
1290 
1291     auto locked_chain = pwallet->chain().lock();
1292     LOCK(pwallet->cs_wallet);
1293 
1294     return ListReceived(*locked_chain, pwallet, request.params, true);
1295 }
1296 
MaybePushAddress(UniValue & entry,const CTxDestination & dest)1297 static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
1298 {
1299     if (IsValidDestination(dest)) {
1300         entry.pushKV("address", EncodeDestination(dest));
1301     }
1302 }
1303 
1304 /**
1305  * List transactions based on the given criteria.
1306  *
1307  * @param  pwallet        The wallet.
1308  * @param  wtx            The wallet transaction.
1309  * @param  nMinDepth      The minimum confirmation depth.
1310  * @param  fLong          Whether to include the JSON version of the transaction.
1311  * @param  ret            The UniValue into which the result is stored.
1312  * @param  filter_ismine  The "is mine" filter flags.
1313  * @param  filter_label   Optional label string to filter incoming transactions.
1314  */
ListTransactions(interfaces::Chain::Lock & locked_chain,CWallet * const pwallet,const CWalletTx & wtx,int nMinDepth,bool fLong,UniValue & ret,const isminefilter & filter_ismine,const std::string * filter_label)1315 static void ListTransactions(interfaces::Chain::Lock& locked_chain, CWallet* const pwallet, const CWalletTx& wtx, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter_ismine, const std::string* filter_label) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
1316 {
1317     CAmount nFee;
1318     std::list<COutputEntry> listReceived;
1319     std::list<COutputEntry> listSent;
1320 
1321     wtx.GetAmounts(listReceived, listSent, nFee, filter_ismine);
1322 
1323     bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
1324 
1325     // Sent
1326     if (!filter_label)
1327     {
1328         for (const COutputEntry& s : listSent)
1329         {
1330             UniValue entry(UniValue::VOBJ);
1331             if (involvesWatchonly || (::IsMine(*pwallet, s.destination) & ISMINE_WATCH_ONLY)) {
1332                 entry.pushKV("involvesWatchonly", true);
1333             }
1334             MaybePushAddress(entry, s.destination);
1335             entry.pushKV("category", "send");
1336             entry.pushKV("amount", ValueFromAmount(-s.amount));
1337             if (pwallet->mapAddressBook.count(s.destination)) {
1338                 entry.pushKV("label", pwallet->mapAddressBook[s.destination].name);
1339             }
1340             entry.pushKV("vout", s.vout);
1341             entry.pushKV("fee", ValueFromAmount(-nFee));
1342             if (fLong)
1343                 WalletTxToJSON(pwallet->chain(), locked_chain, wtx, entry);
1344             entry.pushKV("abandoned", wtx.isAbandoned());
1345             ret.push_back(entry);
1346         }
1347     }
1348 
1349     // Received
1350     if (listReceived.size() > 0 && wtx.GetDepthInMainChain(locked_chain) >= nMinDepth)
1351     {
1352         for (const COutputEntry& r : listReceived)
1353         {
1354             std::string label;
1355             if (pwallet->mapAddressBook.count(r.destination)) {
1356                 label = pwallet->mapAddressBook[r.destination].name;
1357             }
1358             if (filter_label && label != *filter_label) {
1359                 continue;
1360             }
1361             UniValue entry(UniValue::VOBJ);
1362             if (involvesWatchonly || (::IsMine(*pwallet, r.destination) & ISMINE_WATCH_ONLY)) {
1363                 entry.pushKV("involvesWatchonly", true);
1364             }
1365             MaybePushAddress(entry, r.destination);
1366             if (wtx.IsCoinBase())
1367             {
1368                 if (wtx.GetDepthInMainChain(locked_chain) < 1)
1369                     entry.pushKV("category", "orphan");
1370                 else if (wtx.IsImmatureCoinBase(locked_chain))
1371                     entry.pushKV("category", "immature");
1372                 else
1373                     entry.pushKV("category", "generate");
1374             }
1375             else
1376             {
1377                 entry.pushKV("category", "receive");
1378             }
1379             entry.pushKV("amount", ValueFromAmount(r.amount));
1380             if (pwallet->mapAddressBook.count(r.destination)) {
1381                 entry.pushKV("label", label);
1382             }
1383             entry.pushKV("vout", r.vout);
1384             if (fLong)
1385                 WalletTxToJSON(pwallet->chain(), locked_chain, wtx, entry);
1386             ret.push_back(entry);
1387         }
1388     }
1389 }
1390 
listtransactions(const JSONRPCRequest & request)1391 UniValue listtransactions(const JSONRPCRequest& request)
1392 {
1393     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1394     CWallet* const pwallet = wallet.get();
1395 
1396     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
1397         return NullUniValue;
1398     }
1399 
1400     if (request.fHelp || request.params.size() > 4)
1401         throw std::runtime_error(
1402             RPCHelpMan{"listtransactions",
1403                 "\nIf a label name is provided, this will return only incoming transactions paying to addresses with the specified label.\n"
1404                 "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n",
1405                 {
1406                     {"label", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If set, should be a valid label name to return only incoming transactions\n"
1407             "              with the specified label, or \"*\" to disable filtering and return all transactions."},
1408                     {"count", RPCArg::Type::NUM, /* default */ "10", "The number of transactions to return"},
1409                     {"skip", RPCArg::Type::NUM, /* default */ "0", "The number of transactions to skip"},
1410                     {"include_watchonly", RPCArg::Type::BOOL, /* default */ "false", "Include transactions to watch-only addresses (see 'importaddress')"},
1411                 },
1412                 RPCResult{
1413             "[\n"
1414             "  {\n"
1415             "    \"address\":\"address\",    (string) The litecoin address of the transaction.\n"
1416             "    \"category\":               (string) The transaction category.\n"
1417             "                \"send\"                  Transactions sent.\n"
1418             "                \"receive\"               Non-coinbase transactions received.\n"
1419             "                \"generate\"              Coinbase transactions received with more than 100 confirmations.\n"
1420             "                \"immature\"              Coinbase transactions received with 100 or fewer confirmations.\n"
1421             "                \"orphan\"                Orphaned coinbase transactions received.\n"
1422             "    \"amount\": x.xxx,          (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and is positive\n"
1423             "                                        for all other categories\n"
1424             "    \"label\": \"label\",       (string) A comment for the address/transaction, if any\n"
1425             "    \"vout\": n,                (numeric) the vout value\n"
1426             "    \"fee\": x.xxx,             (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
1427             "                                         'send' category of transactions.\n"
1428             "    \"confirmations\": n,       (numeric) The number of confirmations for the transaction. Negative confirmations indicate the\n"
1429             "                                         transaction conflicts with the block chain\n"
1430             "    \"trusted\": xxx,           (bool) Whether we consider the outputs of this unconfirmed transaction safe to spend.\n"
1431             "    \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction.\n"
1432             "    \"blockindex\": n,          (numeric) The index of the transaction in the block that includes it.\n"
1433             "    \"blocktime\": xxx,         (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
1434             "    \"txid\": \"transactionid\", (string) The transaction id.\n"
1435             "    \"time\": xxx,              (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
1436             "    \"timereceived\": xxx,      (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT).\n"
1437             "    \"comment\": \"...\",       (string) If a comment is associated with the transaction.\n"
1438             "    \"bip125-replaceable\": \"yes|no|unknown\",  (string) Whether this transaction could be replaced due to BIP125 (replace-by-fee);\n"
1439             "                                                     may be unknown for unconfirmed transactions not in the mempool\n"
1440             "    \"abandoned\": xxx          (bool) 'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
1441             "                                         'send' category of transactions.\n"
1442             "  }\n"
1443             "]\n"
1444                 },
1445                 RPCExamples{
1446             "\nList the most recent 10 transactions in the systems\n"
1447             + HelpExampleCli("listtransactions", "") +
1448             "\nList transactions 100 to 120\n"
1449             + HelpExampleCli("listtransactions", "\"*\" 20 100") +
1450             "\nAs a JSON-RPC call\n"
1451             + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
1452                 },
1453             }.ToString());
1454 
1455     // Make sure the results are valid at least up to the most recent block
1456     // the user could have gotten from another RPC command prior to now
1457     pwallet->BlockUntilSyncedToCurrentChain();
1458 
1459     const std::string* filter_label = nullptr;
1460     if (!request.params[0].isNull() && request.params[0].get_str() != "*") {
1461         filter_label = &request.params[0].get_str();
1462         if (filter_label->empty()) {
1463             throw JSONRPCError(RPC_INVALID_PARAMETER, "Label argument must be a valid label name or \"*\".");
1464         }
1465     }
1466     int nCount = 10;
1467     if (!request.params[1].isNull())
1468         nCount = request.params[1].get_int();
1469     int nFrom = 0;
1470     if (!request.params[2].isNull())
1471         nFrom = request.params[2].get_int();
1472     isminefilter filter = ISMINE_SPENDABLE;
1473     if(!request.params[3].isNull())
1474         if(request.params[3].get_bool())
1475             filter = filter | ISMINE_WATCH_ONLY;
1476 
1477     if (nCount < 0)
1478         throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1479     if (nFrom < 0)
1480         throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1481 
1482     UniValue ret(UniValue::VARR);
1483 
1484     {
1485         auto locked_chain = pwallet->chain().lock();
1486         LOCK(pwallet->cs_wallet);
1487 
1488         const CWallet::TxItems & txOrdered = pwallet->wtxOrdered;
1489 
1490         // iterate backwards until we have nCount items to return:
1491         for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1492         {
1493             CWalletTx *const pwtx = (*it).second;
1494             ListTransactions(*locked_chain, pwallet, *pwtx, 0, true, ret, filter, filter_label);
1495             if ((int)ret.size() >= (nCount+nFrom)) break;
1496         }
1497     }
1498 
1499     // ret is newest to oldest
1500 
1501     if (nFrom > (int)ret.size())
1502         nFrom = ret.size();
1503     if ((nFrom + nCount) > (int)ret.size())
1504         nCount = ret.size() - nFrom;
1505 
1506     std::vector<UniValue> arrTmp = ret.getValues();
1507 
1508     std::vector<UniValue>::iterator first = arrTmp.begin();
1509     std::advance(first, nFrom);
1510     std::vector<UniValue>::iterator last = arrTmp.begin();
1511     std::advance(last, nFrom+nCount);
1512 
1513     if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end());
1514     if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first);
1515 
1516     std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest
1517 
1518     ret.clear();
1519     ret.setArray();
1520     ret.push_backV(arrTmp);
1521 
1522     return ret;
1523 }
1524 
listsinceblock(const JSONRPCRequest & request)1525 static UniValue listsinceblock(const JSONRPCRequest& request)
1526 {
1527     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1528     CWallet* const pwallet = wallet.get();
1529 
1530     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
1531         return NullUniValue;
1532     }
1533 
1534     if (request.fHelp || request.params.size() > 4)
1535         throw std::runtime_error(
1536             RPCHelpMan{"listsinceblock",
1537                 "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted.\n"
1538                 "If \"blockhash\" is no longer a part of the main chain, transactions from the fork point onward are included.\n"
1539                 "Additionally, if include_removed is set, transactions affecting the wallet which were removed are returned in the \"removed\" array.\n",
1540                 {
1541                     {"blockhash", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If set, the block hash to list transactions since, otherwise list all transactions."},
1542                     {"target_confirmations", RPCArg::Type::NUM, /* default */ "1", "Return the nth block hash from the main chain. e.g. 1 would mean the best block hash. Note: this is not used as a filter, but only affects [lastblock] in the return value"},
1543                     {"include_watchonly", RPCArg::Type::BOOL, /* default */ "false", "Include transactions to watch-only addresses (see 'importaddress')"},
1544                     {"include_removed", RPCArg::Type::BOOL, /* default */ "true", "Show transactions that were removed due to a reorg in the \"removed\" array\n"
1545             "                                                           (not guaranteed to work on pruned nodes)"},
1546                 },
1547                 RPCResult{
1548             "{\n"
1549             "  \"transactions\": [\n"
1550             "    \"address\":\"address\",    (string) The litecoin address of the transaction.\n"
1551             "    \"category\":               (string) The transaction category.\n"
1552             "                \"send\"                  Transactions sent.\n"
1553             "                \"receive\"               Non-coinbase transactions received.\n"
1554             "                \"generate\"              Coinbase transactions received with more than 100 confirmations.\n"
1555             "                \"immature\"              Coinbase transactions received with 100 or fewer confirmations.\n"
1556             "                \"orphan\"                Orphaned coinbase transactions received.\n"
1557             "    \"amount\": x.xxx,          (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and is positive\n"
1558             "                                         for all other categories\n"
1559             "    \"vout\" : n,               (numeric) the vout value\n"
1560             "    \"fee\": x.xxx,             (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the 'send' category of transactions.\n"
1561             "    \"confirmations\": n,       (numeric) The number of confirmations for the transaction.\n"
1562             "                                          When it's < 0, it means the transaction conflicted that many blocks ago.\n"
1563             "    \"blockhash\": \"hashvalue\",     (string) The block hash containing the transaction.\n"
1564             "    \"blockindex\": n,          (numeric) The index of the transaction in the block that includes it.\n"
1565             "    \"blocktime\": xxx,         (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
1566             "    \"txid\": \"transactionid\",  (string) The transaction id.\n"
1567             "    \"time\": xxx,              (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
1568             "    \"timereceived\": xxx,      (numeric) The time received in seconds since epoch (Jan 1 1970 GMT).\n"
1569             "    \"bip125-replaceable\": \"yes|no|unknown\",  (string) Whether this transaction could be replaced due to BIP125 (replace-by-fee);\n"
1570             "                                                   may be unknown for unconfirmed transactions not in the mempool\n"
1571             "    \"abandoned\": xxx,         (bool) 'true' if the transaction has been abandoned (inputs are respendable). Only available for the 'send' category of transactions.\n"
1572             "    \"comment\": \"...\",       (string) If a comment is associated with the transaction.\n"
1573             "    \"label\" : \"label\"       (string) A comment for the address/transaction, if any\n"
1574             "    \"to\": \"...\",            (string) If a comment to is associated with the transaction.\n"
1575             "  ],\n"
1576             "  \"removed\": [\n"
1577             "    <structure is the same as \"transactions\" above, only present if include_removed=true>\n"
1578             "    Note: transactions that were re-added in the active chain will appear as-is in this array, and may thus have a positive confirmation count.\n"
1579             "  ],\n"
1580             "  \"lastblock\": \"lastblockhash\"     (string) The hash of the block (target_confirmations-1) from the best block on the main chain. This is typically used to feed back into listsinceblock the next time you call it. So you would generally use a target_confirmations of say 6, so you will be continually re-notified of transactions until they've reached 6 confirmations plus any new ones\n"
1581             "}\n"
1582                 },
1583                 RPCExamples{
1584                     HelpExampleCli("listsinceblock", "")
1585             + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
1586             + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
1587                 },
1588             }.ToString());
1589 
1590     // Make sure the results are valid at least up to the most recent block
1591     // the user could have gotten from another RPC command prior to now
1592     pwallet->BlockUntilSyncedToCurrentChain();
1593 
1594     auto locked_chain = pwallet->chain().lock();
1595     LOCK(pwallet->cs_wallet);
1596 
1597     // The way the 'height' is initialized is just a workaround for the gcc bug #47679 since version 4.6.0.
1598     Optional<int> height = MakeOptional(false, int()); // Height of the specified block or the common ancestor, if the block provided was in a deactivated chain.
1599     Optional<int> altheight; // Height of the specified block, even if it's in a deactivated chain.
1600     int target_confirms = 1;
1601     isminefilter filter = ISMINE_SPENDABLE;
1602 
1603     uint256 blockId;
1604     if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
1605         blockId = ParseHashV(request.params[0], "blockhash");
1606         height = locked_chain->findFork(blockId, &altheight);
1607         if (!height) {
1608             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1609         }
1610     }
1611 
1612     if (!request.params[1].isNull()) {
1613         target_confirms = request.params[1].get_int();
1614 
1615         if (target_confirms < 1) {
1616             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1617         }
1618     }
1619 
1620     if (!request.params[2].isNull() && request.params[2].get_bool()) {
1621         filter = filter | ISMINE_WATCH_ONLY;
1622     }
1623 
1624     bool include_removed = (request.params[3].isNull() || request.params[3].get_bool());
1625 
1626     const Optional<int> tip_height = locked_chain->getHeight();
1627     int depth = tip_height && height ? (1 + *tip_height - *height) : -1;
1628 
1629     UniValue transactions(UniValue::VARR);
1630 
1631     for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
1632         CWalletTx tx = pairWtx.second;
1633 
1634         if (depth == -1 || tx.GetDepthInMainChain(*locked_chain) < depth) {
1635             ListTransactions(*locked_chain, pwallet, tx, 0, true, transactions, filter, nullptr /* filter_label */);
1636         }
1637     }
1638 
1639     // when a reorg'd block is requested, we also list any relevant transactions
1640     // in the blocks of the chain that was detached
1641     UniValue removed(UniValue::VARR);
1642     while (include_removed && altheight && *altheight > *height) {
1643         CBlock block;
1644         if (!pwallet->chain().findBlock(blockId, &block) || block.IsNull()) {
1645             throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
1646         }
1647         for (const CTransactionRef& tx : block.vtx) {
1648             auto it = pwallet->mapWallet.find(tx->GetHash());
1649             if (it != pwallet->mapWallet.end()) {
1650                 // We want all transactions regardless of confirmation count to appear here,
1651                 // even negative confirmation ones, hence the big negative.
1652                 ListTransactions(*locked_chain, pwallet, it->second, -100000000, true, removed, filter, nullptr /* filter_label */);
1653             }
1654         }
1655         blockId = block.hashPrevBlock;
1656         --*altheight;
1657     }
1658 
1659     int last_height = tip_height ? *tip_height + 1 - target_confirms : -1;
1660     uint256 lastblock = last_height >= 0 ? locked_chain->getBlockHash(last_height) : uint256();
1661 
1662     UniValue ret(UniValue::VOBJ);
1663     ret.pushKV("transactions", transactions);
1664     if (include_removed) ret.pushKV("removed", removed);
1665     ret.pushKV("lastblock", lastblock.GetHex());
1666 
1667     return ret;
1668 }
1669 
gettransaction(const JSONRPCRequest & request)1670 static UniValue gettransaction(const JSONRPCRequest& request)
1671 {
1672     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1673     CWallet* const pwallet = wallet.get();
1674 
1675     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
1676         return NullUniValue;
1677     }
1678 
1679     if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
1680         throw std::runtime_error(
1681             RPCHelpMan{"gettransaction",
1682                 "\nGet detailed information about in-wallet transaction <txid>\n",
1683                 {
1684                     {"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
1685                     {"include_watchonly", RPCArg::Type::BOOL, /* default */ "false", "Whether to include watch-only addresses in balance calculation and details[]"},
1686                 },
1687                 RPCResult{
1688             "{\n"
1689             "  \"amount\" : x.xxx,        (numeric) The transaction amount in " + CURRENCY_UNIT + "\n"
1690             "  \"fee\": x.xxx,            (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
1691             "                              'send' category of transactions.\n"
1692             "  \"confirmations\" : n,     (numeric) The number of confirmations\n"
1693             "  \"blockhash\" : \"hash\",  (string) The block hash\n"
1694             "  \"blockindex\" : xx,       (numeric) The index of the transaction in the block that includes it\n"
1695             "  \"blocktime\" : ttt,       (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
1696             "  \"txid\" : \"transactionid\",   (string) The transaction id.\n"
1697             "  \"time\" : ttt,            (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
1698             "  \"timereceived\" : ttt,    (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
1699             "  \"bip125-replaceable\": \"yes|no|unknown\",  (string) Whether this transaction could be replaced due to BIP125 (replace-by-fee);\n"
1700             "                                                   may be unknown for unconfirmed transactions not in the mempool\n"
1701             "  \"details\" : [\n"
1702             "    {\n"
1703             "      \"address\" : \"address\",          (string) The litecoin address involved in the transaction\n"
1704             "      \"category\" :                      (string) The transaction category.\n"
1705             "                   \"send\"                  Transactions sent.\n"
1706             "                   \"receive\"               Non-coinbase transactions received.\n"
1707             "                   \"generate\"              Coinbase transactions received with more than 100 confirmations.\n"
1708             "                   \"immature\"              Coinbase transactions received with 100 or fewer confirmations.\n"
1709             "                   \"orphan\"                Orphaned coinbase transactions received.\n"
1710             "      \"amount\" : x.xxx,                 (numeric) The amount in " + CURRENCY_UNIT + "\n"
1711             "      \"label\" : \"label\",              (string) A comment for the address/transaction, if any\n"
1712             "      \"vout\" : n,                       (numeric) the vout value\n"
1713             "      \"fee\": x.xxx,                     (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
1714             "                                           'send' category of transactions.\n"
1715             "      \"abandoned\": xxx                  (bool) 'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
1716             "                                           'send' category of transactions.\n"
1717             "    }\n"
1718             "    ,...\n"
1719             "  ],\n"
1720             "  \"hex\" : \"data\"         (string) Raw data for transaction\n"
1721             "}\n"
1722                 },
1723                 RPCExamples{
1724                     HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1725             + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
1726             + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1727                 },
1728             }.ToString());
1729 
1730     // Make sure the results are valid at least up to the most recent block
1731     // the user could have gotten from another RPC command prior to now
1732     pwallet->BlockUntilSyncedToCurrentChain();
1733 
1734     auto locked_chain = pwallet->chain().lock();
1735     LOCK(pwallet->cs_wallet);
1736 
1737     uint256 hash(ParseHashV(request.params[0], "txid"));
1738 
1739     isminefilter filter = ISMINE_SPENDABLE;
1740     if(!request.params[1].isNull())
1741         if(request.params[1].get_bool())
1742             filter = filter | ISMINE_WATCH_ONLY;
1743 
1744     UniValue entry(UniValue::VOBJ);
1745     auto it = pwallet->mapWallet.find(hash);
1746     if (it == pwallet->mapWallet.end()) {
1747         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
1748     }
1749     const CWalletTx& wtx = it->second;
1750 
1751     CAmount nCredit = wtx.GetCredit(*locked_chain, filter);
1752     CAmount nDebit = wtx.GetDebit(filter);
1753     CAmount nNet = nCredit - nDebit;
1754     CAmount nFee = (wtx.IsFromMe(filter) ? wtx.tx->GetValueOut() - nDebit : 0);
1755 
1756     entry.pushKV("amount", ValueFromAmount(nNet - nFee));
1757     if (wtx.IsFromMe(filter))
1758         entry.pushKV("fee", ValueFromAmount(nFee));
1759 
1760     WalletTxToJSON(pwallet->chain(), *locked_chain, wtx, entry);
1761 
1762     UniValue details(UniValue::VARR);
1763     ListTransactions(*locked_chain, pwallet, wtx, 0, false, details, filter, nullptr /* filter_label */);
1764     entry.pushKV("details", details);
1765 
1766     std::string strHex = EncodeHexTx(*wtx.tx, RPCSerializationFlags());
1767     entry.pushKV("hex", strHex);
1768 
1769     return entry;
1770 }
1771 
abandontransaction(const JSONRPCRequest & request)1772 static UniValue abandontransaction(const JSONRPCRequest& request)
1773 {
1774     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1775     CWallet* const pwallet = wallet.get();
1776 
1777     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
1778         return NullUniValue;
1779     }
1780 
1781     if (request.fHelp || request.params.size() != 1) {
1782         throw std::runtime_error(
1783             RPCHelpMan{"abandontransaction",
1784                 "\nMark in-wallet transaction <txid> as abandoned\n"
1785                 "This will mark this transaction and all its in-wallet descendants as abandoned which will allow\n"
1786                 "for their inputs to be respent.  It can be used to replace \"stuck\" or evicted transactions.\n"
1787                 "It only works on transactions which are not included in a block and are not currently in the mempool.\n"
1788                 "It has no effect on transactions which are already abandoned.\n",
1789                 {
1790                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
1791                 },
1792                 RPCResults{},
1793                 RPCExamples{
1794                     HelpExampleCli("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1795             + HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1796                 },
1797             }.ToString());
1798     }
1799 
1800     // Make sure the results are valid at least up to the most recent block
1801     // the user could have gotten from another RPC command prior to now
1802     pwallet->BlockUntilSyncedToCurrentChain();
1803 
1804     auto locked_chain = pwallet->chain().lock();
1805     LOCK(pwallet->cs_wallet);
1806 
1807     uint256 hash(ParseHashV(request.params[0], "txid"));
1808 
1809     if (!pwallet->mapWallet.count(hash)) {
1810         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
1811     }
1812     if (!pwallet->AbandonTransaction(*locked_chain, hash)) {
1813         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not eligible for abandonment");
1814     }
1815 
1816     return NullUniValue;
1817 }
1818 
1819 
backupwallet(const JSONRPCRequest & request)1820 static UniValue backupwallet(const JSONRPCRequest& request)
1821 {
1822     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1823     CWallet* const pwallet = wallet.get();
1824 
1825     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
1826         return NullUniValue;
1827     }
1828 
1829     if (request.fHelp || request.params.size() != 1)
1830         throw std::runtime_error(
1831             RPCHelpMan{"backupwallet",
1832                 "\nSafely copies current wallet file to destination, which can be a directory or a path with filename.\n",
1833                 {
1834                     {"destination", RPCArg::Type::STR, RPCArg::Optional::NO, "The destination directory or file"},
1835                 },
1836                 RPCResults{},
1837                 RPCExamples{
1838                     HelpExampleCli("backupwallet", "\"backup.dat\"")
1839             + HelpExampleRpc("backupwallet", "\"backup.dat\"")
1840                 },
1841             }.ToString());
1842 
1843     // Make sure the results are valid at least up to the most recent block
1844     // the user could have gotten from another RPC command prior to now
1845     pwallet->BlockUntilSyncedToCurrentChain();
1846 
1847     auto locked_chain = pwallet->chain().lock();
1848     LOCK(pwallet->cs_wallet);
1849 
1850     std::string strDest = request.params[0].get_str();
1851     if (!pwallet->BackupWallet(strDest)) {
1852         throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1853     }
1854 
1855     return NullUniValue;
1856 }
1857 
1858 
keypoolrefill(const JSONRPCRequest & request)1859 static UniValue keypoolrefill(const JSONRPCRequest& request)
1860 {
1861     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1862     CWallet* const pwallet = wallet.get();
1863 
1864     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
1865         return NullUniValue;
1866     }
1867 
1868     if (request.fHelp || request.params.size() > 1)
1869         throw std::runtime_error(
1870             RPCHelpMan{"keypoolrefill",
1871                 "\nFills the keypool."+
1872                     HelpRequiringPassphrase(pwallet) + "\n",
1873                 {
1874                     {"newsize", RPCArg::Type::NUM, /* default */ "100", "The new keypool size"},
1875                 },
1876                 RPCResults{},
1877                 RPCExamples{
1878                     HelpExampleCli("keypoolrefill", "")
1879             + HelpExampleRpc("keypoolrefill", "")
1880                 },
1881             }.ToString());
1882 
1883     if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
1884         throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
1885     }
1886 
1887     auto locked_chain = pwallet->chain().lock();
1888     LOCK(pwallet->cs_wallet);
1889 
1890     // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
1891     unsigned int kpSize = 0;
1892     if (!request.params[0].isNull()) {
1893         if (request.params[0].get_int() < 0)
1894             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
1895         kpSize = (unsigned int)request.params[0].get_int();
1896     }
1897 
1898     EnsureWalletIsUnlocked(pwallet);
1899     pwallet->TopUpKeyPool(kpSize);
1900 
1901     if (pwallet->GetKeyPoolSize() < kpSize) {
1902         throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1903     }
1904 
1905     return NullUniValue;
1906 }
1907 
1908 
walletpassphrase(const JSONRPCRequest & request)1909 static UniValue walletpassphrase(const JSONRPCRequest& request)
1910 {
1911     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1912     CWallet* const pwallet = wallet.get();
1913 
1914     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
1915         return NullUniValue;
1916     }
1917 
1918     if (request.fHelp || request.params.size() != 2) {
1919         throw std::runtime_error(
1920             RPCHelpMan{"walletpassphrase",
1921                 "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
1922                 "This is needed prior to performing transactions related to private keys such as sending litecoins\n"
1923             "\nNote:\n"
1924             "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
1925             "time that overrides the old one.\n",
1926                 {
1927                     {"passphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet passphrase"},
1928                     {"timeout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The time to keep the decryption key in seconds; capped at 100000000 (~3 years)."},
1929                 },
1930                 RPCResults{},
1931                 RPCExamples{
1932             "\nUnlock the wallet for 60 seconds\n"
1933             + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
1934             "\nLock the wallet again (before 60 seconds)\n"
1935             + HelpExampleCli("walletlock", "") +
1936             "\nAs a JSON-RPC call\n"
1937             + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
1938                 },
1939             }.ToString());
1940     }
1941 
1942     int64_t nSleepTime;
1943     {
1944         auto locked_chain = pwallet->chain().lock();
1945         LOCK(pwallet->cs_wallet);
1946 
1947         if (!pwallet->IsCrypted()) {
1948             throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1949         }
1950 
1951         // Note that the walletpassphrase is stored in request.params[0] which is not mlock()ed
1952         SecureString strWalletPass;
1953         strWalletPass.reserve(100);
1954         // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1955         // Alternately, find a way to make request.params[0] mlock()'d to begin with.
1956         strWalletPass = request.params[0].get_str().c_str();
1957 
1958         // Get the timeout
1959         nSleepTime = request.params[1].get_int64();
1960         // Timeout cannot be negative, otherwise it will relock immediately
1961         if (nSleepTime < 0) {
1962             throw JSONRPCError(RPC_INVALID_PARAMETER, "Timeout cannot be negative.");
1963         }
1964         // Clamp timeout
1965         constexpr int64_t MAX_SLEEP_TIME = 100000000; // larger values trigger a macos/libevent bug?
1966         if (nSleepTime > MAX_SLEEP_TIME) {
1967             nSleepTime = MAX_SLEEP_TIME;
1968         }
1969 
1970         if (strWalletPass.empty()) {
1971             throw JSONRPCError(RPC_INVALID_PARAMETER, "passphrase can not be empty");
1972         }
1973 
1974         if (!pwallet->Unlock(strWalletPass)) {
1975             throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1976         }
1977 
1978         pwallet->TopUpKeyPool();
1979 
1980         pwallet->nRelockTime = GetTime() + nSleepTime;
1981     }
1982 
1983     // rpcRunLater must be called without cs_wallet held otherwise a deadlock
1984     // can occur. The deadlock would happen when RPCRunLater removes the
1985     // previous timer (and waits for the callback to finish if already running)
1986     // and the callback locks cs_wallet.
1987     AssertLockNotHeld(wallet->cs_wallet);
1988     // Keep a weak pointer to the wallet so that it is possible to unload the
1989     // wallet before the following callback is called. If a valid shared pointer
1990     // is acquired in the callback then the wallet is still loaded.
1991     std::weak_ptr<CWallet> weak_wallet = wallet;
1992     RPCRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), [weak_wallet] {
1993         if (auto shared_wallet = weak_wallet.lock()) {
1994             LOCK(shared_wallet->cs_wallet);
1995             shared_wallet->Lock();
1996             shared_wallet->nRelockTime = 0;
1997         }
1998     }, nSleepTime);
1999 
2000     return NullUniValue;
2001 }
2002 
2003 
walletpassphrasechange(const JSONRPCRequest & request)2004 static UniValue walletpassphrasechange(const JSONRPCRequest& request)
2005 {
2006     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2007     CWallet* const pwallet = wallet.get();
2008 
2009     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2010         return NullUniValue;
2011     }
2012 
2013     if (request.fHelp || request.params.size() != 2) {
2014         throw std::runtime_error(
2015             RPCHelpMan{"walletpassphrasechange",
2016                 "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n",
2017                 {
2018                     {"oldpassphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The current passphrase"},
2019                     {"newpassphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The new passphrase"},
2020                 },
2021                 RPCResults{},
2022                 RPCExamples{
2023                     HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
2024             + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
2025                 },
2026             }.ToString());
2027     }
2028 
2029     auto locked_chain = pwallet->chain().lock();
2030     LOCK(pwallet->cs_wallet);
2031 
2032     if (!pwallet->IsCrypted()) {
2033         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
2034     }
2035 
2036     // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
2037     // Alternately, find a way to make request.params[0] mlock()'d to begin with.
2038     SecureString strOldWalletPass;
2039     strOldWalletPass.reserve(100);
2040     strOldWalletPass = request.params[0].get_str().c_str();
2041 
2042     SecureString strNewWalletPass;
2043     strNewWalletPass.reserve(100);
2044     strNewWalletPass = request.params[1].get_str().c_str();
2045 
2046     if (strOldWalletPass.empty() || strNewWalletPass.empty()) {
2047         throw JSONRPCError(RPC_INVALID_PARAMETER, "passphrase can not be empty");
2048     }
2049 
2050     if (!pwallet->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) {
2051         throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
2052     }
2053 
2054     return NullUniValue;
2055 }
2056 
2057 
walletlock(const JSONRPCRequest & request)2058 static UniValue walletlock(const JSONRPCRequest& request)
2059 {
2060     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2061     CWallet* const pwallet = wallet.get();
2062 
2063     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2064         return NullUniValue;
2065     }
2066 
2067     if (request.fHelp || request.params.size() != 0) {
2068         throw std::runtime_error(
2069             RPCHelpMan{"walletlock",
2070                 "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
2071                 "After calling this method, you will need to call walletpassphrase again\n"
2072                 "before being able to call any methods which require the wallet to be unlocked.\n",
2073                 {},
2074                 RPCResults{},
2075                 RPCExamples{
2076             "\nSet the passphrase for 2 minutes to perform a transaction\n"
2077             + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
2078             "\nPerform a send (requires passphrase set)\n"
2079             + HelpExampleCli("sendtoaddress", "\"LEr4HnaefWYHbMGXcFp2Po1NPRUeIk8km2\" 1.0") +
2080             "\nClear the passphrase since we are done before 2 minutes is up\n"
2081             + HelpExampleCli("walletlock", "") +
2082             "\nAs a JSON-RPC call\n"
2083             + HelpExampleRpc("walletlock", "")
2084                 },
2085             }.ToString());
2086     }
2087 
2088     auto locked_chain = pwallet->chain().lock();
2089     LOCK(pwallet->cs_wallet);
2090 
2091     if (!pwallet->IsCrypted()) {
2092         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
2093     }
2094 
2095     pwallet->Lock();
2096     pwallet->nRelockTime = 0;
2097 
2098     return NullUniValue;
2099 }
2100 
2101 
encryptwallet(const JSONRPCRequest & request)2102 static UniValue encryptwallet(const JSONRPCRequest& request)
2103 {
2104     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2105     CWallet* const pwallet = wallet.get();
2106 
2107     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2108         return NullUniValue;
2109     }
2110 
2111     if (request.fHelp || request.params.size() != 1) {
2112         throw std::runtime_error(
2113             RPCHelpMan{"encryptwallet",
2114                 "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
2115                 "After this, any calls that interact with private keys such as sending or signing \n"
2116                 "will require the passphrase to be set prior the making these calls.\n"
2117                 "Use the walletpassphrase call for this, and then walletlock call.\n"
2118                 "If the wallet is already encrypted, use the walletpassphrasechange call.\n",
2119                 {
2120                     {"passphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long."},
2121                 },
2122                 RPCResults{},
2123                 RPCExamples{
2124             "\nEncrypt your wallet\n"
2125             + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
2126             "\nNow set the passphrase to use the wallet, such as for signing or sending litecoin\n"
2127             + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
2128             "\nNow we can do something like sign\n"
2129             + HelpExampleCli("signmessage", "\"address\" \"test message\"") +
2130             "\nNow lock the wallet again by removing the passphrase\n"
2131             + HelpExampleCli("walletlock", "") +
2132             "\nAs a JSON-RPC call\n"
2133             + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
2134                 },
2135             }.ToString());
2136     }
2137 
2138     auto locked_chain = pwallet->chain().lock();
2139     LOCK(pwallet->cs_wallet);
2140 
2141     if (pwallet->IsCrypted()) {
2142         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
2143     }
2144 
2145     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2146     // Alternately, find a way to make request.params[0] mlock()'d to begin with.
2147     SecureString strWalletPass;
2148     strWalletPass.reserve(100);
2149     strWalletPass = request.params[0].get_str().c_str();
2150 
2151     if (strWalletPass.empty()) {
2152         throw JSONRPCError(RPC_INVALID_PARAMETER, "passphrase can not be empty");
2153     }
2154 
2155     if (!pwallet->EncryptWallet(strWalletPass)) {
2156         throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
2157     }
2158 
2159     return "wallet encrypted; The keypool has been flushed and a new HD seed was generated (if you are using HD). You need to make a new backup.";
2160 }
2161 
lockunspent(const JSONRPCRequest & request)2162 static UniValue lockunspent(const JSONRPCRequest& request)
2163 {
2164     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2165     CWallet* const pwallet = wallet.get();
2166 
2167     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2168         return NullUniValue;
2169     }
2170 
2171     if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
2172         throw std::runtime_error(
2173             RPCHelpMan{"lockunspent",
2174                 "\nUpdates list of temporarily unspendable outputs.\n"
2175                 "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
2176                 "If no transaction outputs are specified when unlocking then all current locked transaction outputs are unlocked.\n"
2177                 "A locked transaction output will not be chosen by automatic coin selection, when spending litecoins.\n"
2178                 "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
2179                 "is always cleared (by virtue of process exit) when a node stops or fails.\n"
2180                 "Also see the listunspent call\n",
2181                 {
2182                     {"unlock", RPCArg::Type::BOOL, RPCArg::Optional::NO, "Whether to unlock (true) or lock (false) the specified transactions"},
2183                     {"transactions", RPCArg::Type::ARR, /* default */ "empty array", "A json array of objects. Each object the txid (string) vout (numeric).",
2184                         {
2185                             {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
2186                                 {
2187                                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
2188                                     {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
2189                                 },
2190                             },
2191                         },
2192                     },
2193                 },
2194                 RPCResult{
2195             "true|false    (boolean) Whether the command was successful or not\n"
2196                 },
2197                 RPCExamples{
2198             "\nList the unspent transactions\n"
2199             + HelpExampleCli("listunspent", "") +
2200             "\nLock an unspent transaction\n"
2201             + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"daaf44ec1e64e66ffda4a7e195ea60d5c8c8b602fc6bf22928582d3ff2530462\\\",\\\"vout\\\":1}]\"") +
2202             "\nList the locked transactions\n"
2203             + HelpExampleCli("listlockunspent", "") +
2204             "\nUnlock the transaction again\n"
2205             + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2206             "\nAs a JSON-RPC call\n"
2207             + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
2208                 },
2209             }.ToString());
2210 
2211     // Make sure the results are valid at least up to the most recent block
2212     // the user could have gotten from another RPC command prior to now
2213     pwallet->BlockUntilSyncedToCurrentChain();
2214 
2215     auto locked_chain = pwallet->chain().lock();
2216     LOCK(pwallet->cs_wallet);
2217 
2218     RPCTypeCheckArgument(request.params[0], UniValue::VBOOL);
2219 
2220     bool fUnlock = request.params[0].get_bool();
2221 
2222     if (request.params[1].isNull()) {
2223         if (fUnlock)
2224             pwallet->UnlockAllCoins();
2225         return true;
2226     }
2227 
2228     RPCTypeCheckArgument(request.params[1], UniValue::VARR);
2229 
2230     const UniValue& output_params = request.params[1];
2231 
2232     // Create and validate the COutPoints first.
2233 
2234     std::vector<COutPoint> outputs;
2235     outputs.reserve(output_params.size());
2236 
2237     for (unsigned int idx = 0; idx < output_params.size(); idx++) {
2238         const UniValue& o = output_params[idx].get_obj();
2239 
2240         RPCTypeCheckObj(o,
2241             {
2242                 {"txid", UniValueType(UniValue::VSTR)},
2243                 {"vout", UniValueType(UniValue::VNUM)},
2244             });
2245 
2246         const uint256 txid(ParseHashO(o, "txid"));
2247         const int nOutput = find_value(o, "vout").get_int();
2248         if (nOutput < 0) {
2249             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
2250         }
2251 
2252         const COutPoint outpt(txid, nOutput);
2253 
2254         const auto it = pwallet->mapWallet.find(outpt.hash);
2255         if (it == pwallet->mapWallet.end()) {
2256             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, unknown transaction");
2257         }
2258 
2259         const CWalletTx& trans = it->second;
2260 
2261         if (outpt.n >= trans.tx->vout.size()) {
2262             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout index out of bounds");
2263         }
2264 
2265         if (pwallet->IsSpent(*locked_chain, outpt.hash, outpt.n)) {
2266             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected unspent output");
2267         }
2268 
2269         const bool is_locked = pwallet->IsLockedCoin(outpt.hash, outpt.n);
2270 
2271         if (fUnlock && !is_locked) {
2272             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected locked output");
2273         }
2274 
2275         if (!fUnlock && is_locked) {
2276             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output already locked");
2277         }
2278 
2279         outputs.push_back(outpt);
2280     }
2281 
2282     // Atomically set (un)locked status for the outputs.
2283     for (const COutPoint& outpt : outputs) {
2284         if (fUnlock) pwallet->UnlockCoin(outpt);
2285         else pwallet->LockCoin(outpt);
2286     }
2287 
2288     return true;
2289 }
2290 
listlockunspent(const JSONRPCRequest & request)2291 static UniValue listlockunspent(const JSONRPCRequest& request)
2292 {
2293     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2294     CWallet* const pwallet = wallet.get();
2295 
2296     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2297         return NullUniValue;
2298     }
2299 
2300     if (request.fHelp || request.params.size() > 0)
2301         throw std::runtime_error(
2302             RPCHelpMan{"listlockunspent",
2303                 "\nReturns list of temporarily unspendable outputs.\n"
2304                 "See the lockunspent call to lock and unlock transactions for spending.\n",
2305                 {},
2306                 RPCResult{
2307             "[\n"
2308             "  {\n"
2309             "    \"txid\" : \"transactionid\",     (string) The transaction id locked\n"
2310             "    \"vout\" : n                      (numeric) The vout value\n"
2311             "  }\n"
2312             "  ,...\n"
2313             "]\n"
2314                 },
2315                 RPCExamples{
2316             "\nList the unspent transactions\n"
2317             + HelpExampleCli("listunspent", "") +
2318             "\nLock an unspent transaction\n"
2319             + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"daaf44ec1e64e66ffda4a7e195ea60d5c8c8b602fc6bf22928582d3ff2530462\\\",\\\"vout\\\":1}]\"") +
2320             "\nList the locked transactions\n"
2321             + HelpExampleCli("listlockunspent", "") +
2322             "\nUnlock the transaction again\n"
2323             + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2324             "\nAs a JSON-RPC call\n"
2325             + HelpExampleRpc("listlockunspent", "")
2326                 },
2327             }.ToString());
2328 
2329     auto locked_chain = pwallet->chain().lock();
2330     LOCK(pwallet->cs_wallet);
2331 
2332     std::vector<COutPoint> vOutpts;
2333     pwallet->ListLockedCoins(vOutpts);
2334 
2335     UniValue ret(UniValue::VARR);
2336 
2337     for (const COutPoint& outpt : vOutpts) {
2338         UniValue o(UniValue::VOBJ);
2339 
2340         o.pushKV("txid", outpt.hash.GetHex());
2341         o.pushKV("vout", (int)outpt.n);
2342         ret.push_back(o);
2343     }
2344 
2345     return ret;
2346 }
2347 
settxfee(const JSONRPCRequest & request)2348 static UniValue settxfee(const JSONRPCRequest& request)
2349 {
2350     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2351     CWallet* const pwallet = wallet.get();
2352 
2353     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2354         return NullUniValue;
2355     }
2356 
2357     if (request.fHelp || request.params.size() < 1 || request.params.size() > 1) {
2358         throw std::runtime_error(
2359             RPCHelpMan{"settxfee",
2360                 "\nSet the transaction fee per kB for this wallet. Overrides the global -paytxfee command line parameter.\n",
2361                 {
2362                     {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The transaction fee in " + CURRENCY_UNIT + "/kB"},
2363                 },
2364                 RPCResult{
2365             "true|false        (boolean) Returns true if successful\n"
2366                 },
2367                 RPCExamples{
2368                     HelpExampleCli("settxfee", "0.00001")
2369             + HelpExampleRpc("settxfee", "0.00001")
2370                 },
2371             }.ToString());
2372     }
2373 
2374     auto locked_chain = pwallet->chain().lock();
2375     LOCK(pwallet->cs_wallet);
2376 
2377     CAmount nAmount = AmountFromValue(request.params[0]);
2378     CFeeRate tx_fee_rate(nAmount, 1000);
2379     if (tx_fee_rate == 0) {
2380         // automatic selection
2381     } else if (tx_fee_rate < ::minRelayTxFee) {
2382         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than min relay tx fee (%s)", ::minRelayTxFee.ToString()));
2383     } else if (tx_fee_rate < pwallet->m_min_fee) {
2384         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than wallet min fee (%s)", pwallet->m_min_fee.ToString()));
2385     }
2386 
2387     pwallet->m_pay_tx_fee = tx_fee_rate;
2388     return true;
2389 }
2390 
getwalletinfo(const JSONRPCRequest & request)2391 static UniValue getwalletinfo(const JSONRPCRequest& request)
2392 {
2393     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2394     CWallet* const pwallet = wallet.get();
2395 
2396     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2397         return NullUniValue;
2398     }
2399 
2400     if (request.fHelp || request.params.size() != 0)
2401         throw std::runtime_error(
2402             RPCHelpMan{"getwalletinfo",
2403                 "Returns an object containing various wallet state info.\n",
2404                 {},
2405                 RPCResult{
2406             "{\n"
2407             "  \"walletname\": xxxxx,               (string) the wallet name\n"
2408             "  \"walletversion\": xxxxx,            (numeric) the wallet version\n"
2409             "  \"balance\": xxxxxxx,                (numeric) the total confirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
2410             "  \"unconfirmed_balance\": xxx,        (numeric) the total unconfirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
2411             "  \"immature_balance\": xxxxxx,        (numeric) the total immature balance of the wallet in " + CURRENCY_UNIT + "\n"
2412             "  \"txcount\": xxxxxxx,                (numeric) the total number of transactions in the wallet\n"
2413             "  \"keypoololdest\": xxxxxx,           (numeric) the timestamp (seconds since Unix epoch) of the oldest pre-generated key in the key pool\n"
2414             "  \"keypoolsize\": xxxx,               (numeric) how many new keys are pre-generated (only counts external keys)\n"
2415             "  \"keypoolsize_hd_internal\": xxxx,   (numeric) how many new keys are pre-generated for internal use (used for change outputs, only appears if the wallet is using this feature, otherwise external keys are used)\n"
2416             "  \"unlocked_until\": ttt,             (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
2417             "  \"paytxfee\": x.xxxx,                (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n"
2418             "  \"hdseedid\": \"<hash160>\"            (string, optional) the Hash160 of the HD seed (only present when HD is enabled)\n"
2419             "  \"private_keys_enabled\": true|false (boolean) false if privatekeys are disabled for this wallet (enforced watch-only wallet)\n"
2420             "}\n"
2421                 },
2422                 RPCExamples{
2423                     HelpExampleCli("getwalletinfo", "")
2424             + HelpExampleRpc("getwalletinfo", "")
2425                 },
2426             }.ToString());
2427 
2428     // Make sure the results are valid at least up to the most recent block
2429     // the user could have gotten from another RPC command prior to now
2430     pwallet->BlockUntilSyncedToCurrentChain();
2431 
2432     auto locked_chain = pwallet->chain().lock();
2433     LOCK(pwallet->cs_wallet);
2434 
2435     UniValue obj(UniValue::VOBJ);
2436 
2437     size_t kpExternalSize = pwallet->KeypoolCountExternalKeys();
2438     obj.pushKV("walletname", pwallet->GetName());
2439     obj.pushKV("walletversion", pwallet->GetVersion());
2440     obj.pushKV("balance",       ValueFromAmount(pwallet->GetBalance()));
2441     obj.pushKV("unconfirmed_balance", ValueFromAmount(pwallet->GetUnconfirmedBalance()));
2442     obj.pushKV("immature_balance",    ValueFromAmount(pwallet->GetImmatureBalance()));
2443     obj.pushKV("txcount",       (int)pwallet->mapWallet.size());
2444     obj.pushKV("keypoololdest", pwallet->GetOldestKeyPoolTime());
2445     obj.pushKV("keypoolsize", (int64_t)kpExternalSize);
2446     CKeyID seed_id = pwallet->GetHDChain().seed_id;
2447     if (pwallet->CanSupportFeature(FEATURE_HD_SPLIT)) {
2448         obj.pushKV("keypoolsize_hd_internal",   (int64_t)(pwallet->GetKeyPoolSize() - kpExternalSize));
2449     }
2450     if (pwallet->IsCrypted()) {
2451         obj.pushKV("unlocked_until", pwallet->nRelockTime);
2452     }
2453     obj.pushKV("paytxfee", ValueFromAmount(pwallet->m_pay_tx_fee.GetFeePerK()));
2454     if (!seed_id.IsNull()) {
2455         obj.pushKV("hdseedid", seed_id.GetHex());
2456     }
2457     obj.pushKV("private_keys_enabled", !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
2458     return obj;
2459 }
2460 
listwalletdir(const JSONRPCRequest & request)2461 static UniValue listwalletdir(const JSONRPCRequest& request)
2462 {
2463     if (request.fHelp || request.params.size() != 0) {
2464         throw std::runtime_error(
2465             RPCHelpMan{"listwalletdir",
2466                 "Returns a list of wallets in the wallet directory.\n",
2467                 {},
2468                 RPCResult{
2469             "{\n"
2470             "  \"wallets\" : [                (json array of objects)\n"
2471             "    {\n"
2472             "      \"name\" : \"name\"          (string) The wallet name\n"
2473             "    }\n"
2474             "    ,...\n"
2475             "  ]\n"
2476             "}\n"
2477                 },
2478                 RPCExamples{
2479                     HelpExampleCli("listwalletdir", "")
2480             + HelpExampleRpc("listwalletdir", "")
2481                 },
2482             }.ToString());
2483     }
2484 
2485     UniValue wallets(UniValue::VARR);
2486     for (const auto& path : ListWalletDir()) {
2487         UniValue wallet(UniValue::VOBJ);
2488         wallet.pushKV("name", path.string());
2489         wallets.push_back(wallet);
2490     }
2491 
2492     UniValue result(UniValue::VOBJ);
2493     result.pushKV("wallets", wallets);
2494     return result;
2495 }
2496 
listwallets(const JSONRPCRequest & request)2497 static UniValue listwallets(const JSONRPCRequest& request)
2498 {
2499     if (request.fHelp || request.params.size() != 0)
2500         throw std::runtime_error(
2501             RPCHelpMan{"listwallets",
2502                 "Returns a list of currently loaded wallets.\n"
2503                 "For full information on the wallet, use \"getwalletinfo\"\n",
2504                 {},
2505                 RPCResult{
2506             "[                         (json array of strings)\n"
2507             "  \"walletname\"            (string) the wallet name\n"
2508             "   ...\n"
2509             "]\n"
2510                 },
2511                 RPCExamples{
2512                     HelpExampleCli("listwallets", "")
2513             + HelpExampleRpc("listwallets", "")
2514                 },
2515             }.ToString());
2516 
2517     UniValue obj(UniValue::VARR);
2518 
2519     for (const std::shared_ptr<CWallet>& wallet : GetWallets()) {
2520         if (!EnsureWalletIsAvailable(wallet.get(), request.fHelp)) {
2521             return NullUniValue;
2522         }
2523 
2524         LOCK(wallet->cs_wallet);
2525 
2526         obj.push_back(wallet->GetName());
2527     }
2528 
2529     return obj;
2530 }
2531 
loadwallet(const JSONRPCRequest & request)2532 static UniValue loadwallet(const JSONRPCRequest& request)
2533 {
2534     if (request.fHelp || request.params.size() != 1)
2535         throw std::runtime_error(
2536             RPCHelpMan{"loadwallet",
2537                 "\nLoads a wallet from a wallet file or directory."
2538                 "\nNote that all wallet command-line options used when starting litecoind will be"
2539                 "\napplied to the new wallet (eg -zapwallettxes, upgradewallet, rescan, etc).\n",
2540                 {
2541                     {"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet directory or .dat file."},
2542                 },
2543                 RPCResult{
2544             "{\n"
2545             "  \"name\" :    <wallet_name>,        (string) The wallet name if loaded successfully.\n"
2546             "  \"warning\" : <warning>,            (string) Warning message if wallet was not loaded cleanly.\n"
2547             "}\n"
2548                 },
2549                 RPCExamples{
2550                     HelpExampleCli("loadwallet", "\"test.dat\"")
2551             + HelpExampleRpc("loadwallet", "\"test.dat\"")
2552                 },
2553             }.ToString());
2554 
2555     WalletLocation location(request.params[0].get_str());
2556 
2557     if (!location.Exists()) {
2558         throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Wallet " + location.GetName() + " not found.");
2559     } else if (fs::is_directory(location.GetPath())) {
2560         // The given filename is a directory. Check that there's a wallet.dat file.
2561         fs::path wallet_dat_file = location.GetPath() / "wallet.dat";
2562         if (fs::symlink_status(wallet_dat_file).type() == fs::file_not_found) {
2563             throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Directory " + location.GetName() + " does not contain a wallet.dat file.");
2564         }
2565     }
2566 
2567     std::string error, warning;
2568     std::shared_ptr<CWallet> const wallet = LoadWallet(*g_rpc_interfaces->chain, location, error, warning);
2569     if (!wallet) throw JSONRPCError(RPC_WALLET_ERROR, error);
2570 
2571     UniValue obj(UniValue::VOBJ);
2572     obj.pushKV("name", wallet->GetName());
2573     obj.pushKV("warning", warning);
2574 
2575     return obj;
2576 }
2577 
createwallet(const JSONRPCRequest & request)2578 static UniValue createwallet(const JSONRPCRequest& request)
2579 {
2580     if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) {
2581         throw std::runtime_error(
2582             RPCHelpMan{"createwallet",
2583                 "\nCreates and loads a new wallet.\n",
2584                 {
2585                     {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name for the new wallet. If this is a path, the wallet will be created at the path location."},
2586                     {"disable_private_keys", RPCArg::Type::BOOL, /* default */ "false", "Disable the possibility of private keys (only watchonlys are possible in this mode)."},
2587                     {"blank", RPCArg::Type::BOOL, /* default */ "false", "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."},
2588                 },
2589                 RPCResult{
2590             "{\n"
2591             "  \"name\" :    <wallet_name>,        (string) The wallet name if created successfully. If the wallet was created using a full path, the wallet_name will be the full path.\n"
2592             "  \"warning\" : <warning>,            (string) Warning message if wallet was not loaded cleanly.\n"
2593             "}\n"
2594                 },
2595                 RPCExamples{
2596                     HelpExampleCli("createwallet", "\"testwallet\"")
2597             + HelpExampleRpc("createwallet", "\"testwallet\"")
2598                 },
2599             }.ToString());
2600     }
2601     std::string error;
2602     std::string warning;
2603 
2604     uint64_t flags = 0;
2605     if (!request.params[1].isNull() && request.params[1].get_bool()) {
2606         flags |= WALLET_FLAG_DISABLE_PRIVATE_KEYS;
2607     }
2608 
2609     if (!request.params[2].isNull() && request.params[2].get_bool()) {
2610         flags |= WALLET_FLAG_BLANK_WALLET;
2611     }
2612 
2613     WalletLocation location(request.params[0].get_str());
2614     if (location.Exists()) {
2615         throw JSONRPCError(RPC_WALLET_ERROR, "Wallet " + location.GetName() + " already exists.");
2616     }
2617 
2618     // Wallet::Verify will check if we're trying to create a wallet with a duplication name.
2619     if (!CWallet::Verify(*g_rpc_interfaces->chain, location, false, error, warning)) {
2620         throw JSONRPCError(RPC_WALLET_ERROR, "Wallet file verification failed: " + error);
2621     }
2622 
2623     std::shared_ptr<CWallet> const wallet = CWallet::CreateWalletFromFile(*g_rpc_interfaces->chain, location, flags);
2624     if (!wallet) {
2625         throw JSONRPCError(RPC_WALLET_ERROR, "Wallet creation failed.");
2626     }
2627     AddWallet(wallet);
2628 
2629     wallet->postInitProcess();
2630 
2631     UniValue obj(UniValue::VOBJ);
2632     obj.pushKV("name", wallet->GetName());
2633     obj.pushKV("warning", warning);
2634 
2635     return obj;
2636 }
2637 
unloadwallet(const JSONRPCRequest & request)2638 static UniValue unloadwallet(const JSONRPCRequest& request)
2639 {
2640     if (request.fHelp || request.params.size() > 1) {
2641         throw std::runtime_error(
2642             RPCHelpMan{"unloadwallet",
2643                 "Unloads the wallet referenced by the request endpoint otherwise unloads the wallet specified in the argument.\n"
2644                 "Specifying the wallet name on a wallet endpoint is invalid.",
2645                 {
2646                     {"wallet_name", RPCArg::Type::STR, /* default */ "the wallet name from the RPC request", "The name of the wallet to unload."},
2647                 },
2648                 RPCResults{},
2649                 RPCExamples{
2650                     HelpExampleCli("unloadwallet", "wallet_name")
2651             + HelpExampleRpc("unloadwallet", "wallet_name")
2652                 },
2653             }.ToString());
2654     }
2655 
2656     std::string wallet_name;
2657     if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
2658         if (!request.params[0].isNull()) {
2659             throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot unload the requested wallet");
2660         }
2661     } else {
2662         wallet_name = request.params[0].get_str();
2663     }
2664 
2665     std::shared_ptr<CWallet> wallet = GetWallet(wallet_name);
2666     if (!wallet) {
2667         throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
2668     }
2669 
2670     // Release the "main" shared pointer and prevent further notifications.
2671     // Note that any attempt to load the same wallet would fail until the wallet
2672     // is destroyed (see CheckUniqueFileid).
2673     if (!RemoveWallet(wallet)) {
2674         throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded");
2675     }
2676 
2677     UnloadWallet(std::move(wallet));
2678 
2679     return NullUniValue;
2680 }
2681 
resendwallettransactions(const JSONRPCRequest & request)2682 static UniValue resendwallettransactions(const JSONRPCRequest& request)
2683 {
2684     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2685     CWallet* const pwallet = wallet.get();
2686 
2687     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2688         return NullUniValue;
2689     }
2690 
2691     if (request.fHelp || request.params.size() != 0)
2692         throw std::runtime_error(
2693             RPCHelpMan{"resendwallettransactions",
2694                 "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
2695                 "Intended only for testing; the wallet code periodically re-broadcasts\n"
2696                 "automatically.\n",
2697                 {},
2698                 RPCResult{
2699             "Returns an RPC error if -walletbroadcast is set to false.\n"
2700             "Returns array of transaction ids that were re-broadcast.\n"
2701                 },
2702                  RPCExamples{""},
2703              }.ToString()
2704             );
2705 
2706     if (!g_connman)
2707         throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
2708 
2709     auto locked_chain = pwallet->chain().lock();
2710     LOCK(pwallet->cs_wallet);
2711 
2712     if (!pwallet->GetBroadcastTransactions()) {
2713         throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet transaction broadcasting is disabled with -walletbroadcast");
2714     }
2715 
2716     std::vector<uint256> txids = pwallet->ResendWalletTransactionsBefore(*locked_chain, GetTime(), g_connman.get());
2717     UniValue result(UniValue::VARR);
2718     for (const uint256& txid : txids)
2719     {
2720         result.push_back(txid.ToString());
2721     }
2722     return result;
2723 }
2724 
listunspent(const JSONRPCRequest & request)2725 static UniValue listunspent(const JSONRPCRequest& request)
2726 {
2727     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2728     CWallet* const pwallet = wallet.get();
2729 
2730     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2731         return NullUniValue;
2732     }
2733 
2734     if (request.fHelp || request.params.size() > 5)
2735         throw std::runtime_error(
2736             RPCHelpMan{"listunspent",
2737                 "\nReturns array of unspent transaction outputs\n"
2738                 "with between minconf and maxconf (inclusive) confirmations.\n"
2739                 "Optionally filter to only include txouts paid to specified addresses.\n",
2740                 {
2741                     {"minconf", RPCArg::Type::NUM, /* default */ "1", "The minimum confirmations to filter"},
2742                     {"maxconf", RPCArg::Type::NUM, /* default */ "9999999", "The maximum confirmations to filter"},
2743                     {"addresses", RPCArg::Type::ARR, /* default */ "empty array", "A json array of litecoin addresses to filter",
2744                         {
2745                             {"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "litecoin address"},
2746                         },
2747                     },
2748                     {"include_unsafe", RPCArg::Type::BOOL, /* default */ "true", "Include outputs that are not safe to spend\n"
2749             "                  See description of \"safe\" attribute below."},
2750                     {"query_options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "JSON with query options",
2751                         {
2752                             {"minimumAmount", RPCArg::Type::AMOUNT, /* default */ "0", "Minimum value of each UTXO in " + CURRENCY_UNIT + ""},
2753                             {"maximumAmount", RPCArg::Type::AMOUNT, /* default */ "unlimited", "Maximum value of each UTXO in " + CURRENCY_UNIT + ""},
2754                             {"maximumCount", RPCArg::Type::NUM, /* default */ "unlimited", "Maximum number of UTXOs"},
2755                             {"minimumSumAmount", RPCArg::Type::AMOUNT, /* default */ "unlimited", "Minimum sum value of all UTXOs in " + CURRENCY_UNIT + ""},
2756                         },
2757                         "query_options"},
2758                 },
2759                 RPCResult{
2760             "[                   (array of json object)\n"
2761             "  {\n"
2762             "    \"txid\" : \"txid\",          (string) the transaction id \n"
2763             "    \"vout\" : n,               (numeric) the vout value\n"
2764             "    \"address\" : \"address\",    (string) the litecoin address\n"
2765             "    \"label\" : \"label\",        (string) The associated label, or \"\" for the default label\n"
2766             "    \"scriptPubKey\" : \"key\",   (string) the script key\n"
2767             "    \"amount\" : x.xxx,         (numeric) the transaction output amount in " + CURRENCY_UNIT + "\n"
2768             "    \"confirmations\" : n,      (numeric) The number of confirmations\n"
2769             "    \"redeemScript\" : \"script\" (string) The redeemScript if scriptPubKey is P2SH\n"
2770             "    \"witnessScript\" : \"script\" (string) witnessScript if the scriptPubKey is P2WSH or P2SH-P2WSH\n"
2771             "    \"spendable\" : xxx,        (bool) Whether we have the private keys to spend this output\n"
2772             "    \"solvable\" : xxx,         (bool) Whether we know how to spend this output, ignoring the lack of keys\n"
2773             "    \"desc\" : xxx,             (string, only when solvable) A descriptor for spending this output\n"
2774             "    \"safe\" : xxx              (bool) Whether this output is considered safe to spend. Unconfirmed transactions\n"
2775             "                              from outside keys and unconfirmed replacement transactions are considered unsafe\n"
2776             "                              and are not eligible for spending by fundrawtransaction and sendtoaddress.\n"
2777             "  }\n"
2778             "  ,...\n"
2779             "]\n"
2780                 },
2781                 RPCExamples{
2782                     HelpExampleCli("listunspent", "")
2783             + HelpExampleCli("listunspent", "6 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
2784             + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
2785             + HelpExampleCli("listunspent", "6 9999999 '[]' true '{ \"minimumAmount\": 0.005 }'")
2786             + HelpExampleRpc("listunspent", "6, 9999999, [] , true, { \"minimumAmount\": 0.005 } ")
2787                 },
2788             }.ToString());
2789 
2790     int nMinDepth = 1;
2791     if (!request.params[0].isNull()) {
2792         RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
2793         nMinDepth = request.params[0].get_int();
2794     }
2795 
2796     int nMaxDepth = 9999999;
2797     if (!request.params[1].isNull()) {
2798         RPCTypeCheckArgument(request.params[1], UniValue::VNUM);
2799         nMaxDepth = request.params[1].get_int();
2800     }
2801 
2802     std::set<CTxDestination> destinations;
2803     if (!request.params[2].isNull()) {
2804         RPCTypeCheckArgument(request.params[2], UniValue::VARR);
2805         UniValue inputs = request.params[2].get_array();
2806         for (unsigned int idx = 0; idx < inputs.size(); idx++) {
2807             const UniValue& input = inputs[idx];
2808             CTxDestination dest = DecodeDestination(input.get_str());
2809             if (!IsValidDestination(dest)) {
2810                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Litecoin address: ") + input.get_str());
2811             }
2812             if (!destinations.insert(dest).second) {
2813                 throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + input.get_str());
2814             }
2815         }
2816     }
2817 
2818     bool include_unsafe = true;
2819     if (!request.params[3].isNull()) {
2820         RPCTypeCheckArgument(request.params[3], UniValue::VBOOL);
2821         include_unsafe = request.params[3].get_bool();
2822     }
2823 
2824     CAmount nMinimumAmount = 0;
2825     CAmount nMaximumAmount = MAX_MONEY;
2826     CAmount nMinimumSumAmount = MAX_MONEY;
2827     uint64_t nMaximumCount = 0;
2828 
2829     if (!request.params[4].isNull()) {
2830         const UniValue& options = request.params[4].get_obj();
2831 
2832         if (options.exists("minimumAmount"))
2833             nMinimumAmount = AmountFromValue(options["minimumAmount"]);
2834 
2835         if (options.exists("maximumAmount"))
2836             nMaximumAmount = AmountFromValue(options["maximumAmount"]);
2837 
2838         if (options.exists("minimumSumAmount"))
2839             nMinimumSumAmount = AmountFromValue(options["minimumSumAmount"]);
2840 
2841         if (options.exists("maximumCount"))
2842             nMaximumCount = options["maximumCount"].get_int64();
2843     }
2844 
2845     // Make sure the results are valid at least up to the most recent block
2846     // the user could have gotten from another RPC command prior to now
2847     pwallet->BlockUntilSyncedToCurrentChain();
2848 
2849     UniValue results(UniValue::VARR);
2850     std::vector<COutput> vecOutputs;
2851     {
2852         auto locked_chain = pwallet->chain().lock();
2853         LOCK(pwallet->cs_wallet);
2854         pwallet->AvailableCoins(*locked_chain, vecOutputs, !include_unsafe, nullptr, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount, nMinDepth, nMaxDepth);
2855     }
2856 
2857     LOCK(pwallet->cs_wallet);
2858 
2859     for (const COutput& out : vecOutputs) {
2860         CTxDestination address;
2861         const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
2862         bool fValidAddress = ExtractDestination(scriptPubKey, address);
2863 
2864         if (destinations.size() && (!fValidAddress || !destinations.count(address)))
2865             continue;
2866 
2867         UniValue entry(UniValue::VOBJ);
2868         entry.pushKV("txid", out.tx->GetHash().GetHex());
2869         entry.pushKV("vout", out.i);
2870 
2871         if (fValidAddress) {
2872             entry.pushKV("address", EncodeDestination(address));
2873 
2874             auto i = pwallet->mapAddressBook.find(address);
2875             if (i != pwallet->mapAddressBook.end()) {
2876                 entry.pushKV("label", i->second.name);
2877             }
2878 
2879             if (scriptPubKey.IsPayToScriptHash()) {
2880                 const CScriptID& hash = boost::get<CScriptID>(address);
2881                 CScript redeemScript;
2882                 if (pwallet->GetCScript(hash, redeemScript)) {
2883                     entry.pushKV("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()));
2884                     // Now check if the redeemScript is actually a P2WSH script
2885                     CTxDestination witness_destination;
2886                     if (redeemScript.IsPayToWitnessScriptHash()) {
2887                         bool extracted = ExtractDestination(redeemScript, witness_destination);
2888                         assert(extracted);
2889                         // Also return the witness script
2890                         const WitnessV0ScriptHash& whash = boost::get<WitnessV0ScriptHash>(witness_destination);
2891                         CScriptID id;
2892                         CRIPEMD160().Write(whash.begin(), whash.size()).Finalize(id.begin());
2893                         CScript witnessScript;
2894                         if (pwallet->GetCScript(id, witnessScript)) {
2895                             entry.pushKV("witnessScript", HexStr(witnessScript.begin(), witnessScript.end()));
2896                         }
2897                     }
2898                 }
2899             } else if (scriptPubKey.IsPayToWitnessScriptHash()) {
2900                 const WitnessV0ScriptHash& whash = boost::get<WitnessV0ScriptHash>(address);
2901                 CScriptID id;
2902                 CRIPEMD160().Write(whash.begin(), whash.size()).Finalize(id.begin());
2903                 CScript witnessScript;
2904                 if (pwallet->GetCScript(id, witnessScript)) {
2905                     entry.pushKV("witnessScript", HexStr(witnessScript.begin(), witnessScript.end()));
2906                 }
2907             }
2908         }
2909 
2910         entry.pushKV("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end()));
2911         entry.pushKV("amount", ValueFromAmount(out.tx->tx->vout[out.i].nValue));
2912         entry.pushKV("confirmations", out.nDepth);
2913         entry.pushKV("spendable", out.fSpendable);
2914         entry.pushKV("solvable", out.fSolvable);
2915         if (out.fSolvable) {
2916             auto descriptor = InferDescriptor(scriptPubKey, *pwallet);
2917             entry.pushKV("desc", descriptor->ToString());
2918         }
2919         entry.pushKV("safe", out.fSafe);
2920         results.push_back(entry);
2921     }
2922 
2923     return results;
2924 }
2925 
FundTransaction(CWallet * const pwallet,CMutableTransaction & tx,CAmount & fee_out,int & change_position,UniValue options)2926 void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& fee_out, int& change_position, UniValue options)
2927 {
2928     // Make sure the results are valid at least up to the most recent block
2929     // the user could have gotten from another RPC command prior to now
2930     pwallet->BlockUntilSyncedToCurrentChain();
2931 
2932     CCoinControl coinControl;
2933     change_position = -1;
2934     bool lockUnspents = false;
2935     UniValue subtractFeeFromOutputs;
2936     std::set<int> setSubtractFeeFromOutputs;
2937 
2938     if (!options.isNull()) {
2939       if (options.type() == UniValue::VBOOL) {
2940         // backward compatibility bool only fallback
2941         coinControl.fAllowWatchOnly = options.get_bool();
2942       }
2943       else {
2944         RPCTypeCheckArgument(options, UniValue::VOBJ);
2945         RPCTypeCheckObj(options,
2946             {
2947                 {"changeAddress", UniValueType(UniValue::VSTR)},
2948                 {"changePosition", UniValueType(UniValue::VNUM)},
2949                 {"change_type", UniValueType(UniValue::VSTR)},
2950                 {"includeWatching", UniValueType(UniValue::VBOOL)},
2951                 {"lockUnspents", UniValueType(UniValue::VBOOL)},
2952                 {"feeRate", UniValueType()}, // will be checked below
2953                 {"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
2954                 {"replaceable", UniValueType(UniValue::VBOOL)},
2955                 {"conf_target", UniValueType(UniValue::VNUM)},
2956                 {"estimate_mode", UniValueType(UniValue::VSTR)},
2957             },
2958             true, true);
2959 
2960         if (options.exists("changeAddress")) {
2961             CTxDestination dest = DecodeDestination(options["changeAddress"].get_str());
2962 
2963             if (!IsValidDestination(dest)) {
2964                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "changeAddress must be a valid litecoin address");
2965             }
2966 
2967             coinControl.destChange = dest;
2968         }
2969 
2970         if (options.exists("changePosition"))
2971             change_position = options["changePosition"].get_int();
2972 
2973         if (options.exists("change_type")) {
2974             if (options.exists("changeAddress")) {
2975                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both changeAddress and address_type options");
2976             }
2977             coinControl.m_change_type = pwallet->m_default_change_type;
2978             if (!ParseOutputType(options["change_type"].get_str(), *coinControl.m_change_type)) {
2979                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown change type '%s'", options["change_type"].get_str()));
2980             }
2981         }
2982 
2983         if (options.exists("includeWatching"))
2984             coinControl.fAllowWatchOnly = options["includeWatching"].get_bool();
2985 
2986         if (options.exists("lockUnspents"))
2987             lockUnspents = options["lockUnspents"].get_bool();
2988 
2989         if (options.exists("feeRate"))
2990         {
2991             coinControl.m_feerate = CFeeRate(AmountFromValue(options["feeRate"]));
2992             coinControl.fOverrideFeeRate = true;
2993         }
2994 
2995         if (options.exists("subtractFeeFromOutputs"))
2996             subtractFeeFromOutputs = options["subtractFeeFromOutputs"].get_array();
2997 
2998         if (options.exists("replaceable")) {
2999             coinControl.m_signal_bip125_rbf = options["replaceable"].get_bool();
3000         }
3001         if (options.exists("conf_target")) {
3002             if (options.exists("feeRate")) {
3003                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both conf_target and feeRate");
3004             }
3005             coinControl.m_confirm_target = ParseConfirmTarget(options["conf_target"]);
3006         }
3007         if (options.exists("estimate_mode")) {
3008             if (options.exists("feeRate")) {
3009                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both estimate_mode and feeRate");
3010             }
3011             if (!FeeModeFromString(options["estimate_mode"].get_str(), coinControl.m_fee_mode)) {
3012                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
3013             }
3014         }
3015       }
3016     }
3017 
3018     if (tx.vout.size() == 0)
3019         throw JSONRPCError(RPC_INVALID_PARAMETER, "TX must have at least one output");
3020 
3021     if (change_position != -1 && (change_position < 0 || (unsigned int)change_position > tx.vout.size()))
3022         throw JSONRPCError(RPC_INVALID_PARAMETER, "changePosition out of bounds");
3023 
3024     for (unsigned int idx = 0; idx < subtractFeeFromOutputs.size(); idx++) {
3025         int pos = subtractFeeFromOutputs[idx].get_int();
3026         if (setSubtractFeeFromOutputs.count(pos))
3027             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, duplicated position: %d", pos));
3028         if (pos < 0)
3029             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, negative position: %d", pos));
3030         if (pos >= int(tx.vout.size()))
3031             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, position too large: %d", pos));
3032         setSubtractFeeFromOutputs.insert(pos);
3033     }
3034 
3035     std::string strFailReason;
3036 
3037     if (!pwallet->FundTransaction(tx, fee_out, change_position, strFailReason, lockUnspents, setSubtractFeeFromOutputs, coinControl)) {
3038         throw JSONRPCError(RPC_WALLET_ERROR, strFailReason);
3039     }
3040 }
3041 
fundrawtransaction(const JSONRPCRequest & request)3042 static UniValue fundrawtransaction(const JSONRPCRequest& request)
3043 {
3044     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3045     CWallet* const pwallet = wallet.get();
3046 
3047     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3048         return NullUniValue;
3049     }
3050 
3051     const RPCHelpMan help{"fundrawtransaction",
3052                 "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
3053                 "This will not modify existing inputs, and will add at most one change output to the outputs.\n"
3054                 "No existing outputs will be modified unless \"subtractFeeFromOutputs\" is specified.\n"
3055                 "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
3056                 "The inputs added will not be signed, use signrawtransactionwithkey\n"
3057                 " or signrawtransactionwithwallet for that.\n"
3058                 "Note that all existing inputs must have their previous output transaction be in the wallet.\n"
3059                 "Note that all inputs selected must be of standard form and P2SH scripts must be\n"
3060                 "in the wallet using importaddress or addmultisigaddress (to calculate fees).\n"
3061                 "You can see whether this is the case by checking the \"solvable\" field in the listunspent output.\n"
3062                 "Only pay-to-pubkey, multisig, and P2SH versions thereof are currently supported for watch-only\n",
3063                 {
3064                     {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
3065                     {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}",
3066                         {
3067                             {"changeAddress", RPCArg::Type::STR, /* default */ "pool address", "The litecoin address to receive the change"},
3068                             {"changePosition", RPCArg::Type::NUM, /* default */ "random", "The index of the change output"},
3069                             {"change_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
3070                             {"includeWatching", RPCArg::Type::BOOL, /* default */ "false", "Also select inputs which are watch only"},
3071                             {"lockUnspents", RPCArg::Type::BOOL, /* default */ "false", "Lock selected unspent outputs"},
3072                             {"feeRate", RPCArg::Type::AMOUNT, /* default */ "not set: makes wallet determine the fee", "Set a specific fee rate in " + CURRENCY_UNIT + "/kB"},
3073                             {"subtractFeeFromOutputs", RPCArg::Type::ARR, /* default */ "empty array", "A json array of integers.\n"
3074                             "                              The fee will be equally deducted from the amount of each specified output.\n"
3075                             "                              Those recipients will receive less litecoins than you enter in their corresponding amount field.\n"
3076                             "                              If no outputs are specified here, the sender pays the fee.",
3077                                 {
3078                                     {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
3079                                 },
3080                             },
3081                             {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n"
3082                             "                              Allows this transaction to be replaced by a transaction with higher fees"},
3083                             {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks)"},
3084                             {"estimate_mode", RPCArg::Type::STR, /* default */ "UNSET", "The fee estimate mode, must be one of:\n"
3085                             "         \"UNSET\"\n"
3086                             "         \"ECONOMICAL\"\n"
3087                             "         \"CONSERVATIVE\""},
3088                         },
3089                         "options"},
3090                     {"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n"
3091                         "If iswitness is not present, heuristic tests will be used in decoding.\n"
3092                         "If true, only witness deserialization will be tried.\n"
3093                         "If false, only non-witness deserialization will be tried.\n"
3094                         "This boolean should reflect whether the transaction has inputs\n"
3095                         "(e.g. fully valid, or on-chain transactions), if known by the caller."
3096                     },
3097                 },
3098                 RPCResult{
3099                             "{\n"
3100                             "  \"hex\":       \"value\", (string)  The resulting raw transaction (hex-encoded string)\n"
3101                             "  \"fee\":       n,         (numeric) Fee in " + CURRENCY_UNIT + " the resulting transaction pays\n"
3102                             "  \"changepos\": n          (numeric) The position of the added change output, or -1\n"
3103                             "}\n"
3104                                 },
3105                                 RPCExamples{
3106                             "\nCreate a transaction with no inputs\n"
3107                             + HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
3108                             "\nAdd sufficient unsigned inputs to meet the output value\n"
3109                             + HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
3110                             "\nSign the transaction\n"
3111                             + HelpExampleCli("signrawtransactionwithwallet", "\"fundedtransactionhex\"") +
3112                             "\nSend the transaction\n"
3113                             + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
3114                                 },
3115     };
3116 
3117     if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
3118         throw std::runtime_error(help.ToString());
3119     }
3120 
3121     RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType(), UniValue::VBOOL});
3122 
3123     // parse hex string from parameter
3124     CMutableTransaction tx;
3125     bool try_witness = request.params[2].isNull() ? true : request.params[2].get_bool();
3126     bool try_no_witness = request.params[2].isNull() ? true : !request.params[2].get_bool();
3127     if (!DecodeHexTx(tx, request.params[0].get_str(), try_no_witness, try_witness)) {
3128         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
3129     }
3130 
3131     CAmount fee;
3132     int change_position;
3133     FundTransaction(pwallet, tx, fee, change_position, request.params[1]);
3134 
3135     UniValue result(UniValue::VOBJ);
3136     result.pushKV("hex", EncodeHexTx(CTransaction(tx)));
3137     result.pushKV("fee", ValueFromAmount(fee));
3138     result.pushKV("changepos", change_position);
3139 
3140     return result;
3141 }
3142 
signrawtransactionwithwallet(const JSONRPCRequest & request)3143 UniValue signrawtransactionwithwallet(const JSONRPCRequest& request)
3144 {
3145     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3146     CWallet* const pwallet = wallet.get();
3147 
3148     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3149         return NullUniValue;
3150     }
3151 
3152     if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
3153         throw std::runtime_error(
3154             RPCHelpMan{"signrawtransactionwithwallet",
3155                 "\nSign inputs for raw transaction (serialized, hex-encoded).\n"
3156                 "The second optional argument (may be null) is an array of previous transaction outputs that\n"
3157                 "this transaction depends on but may not yet be in the block chain." +
3158                     HelpRequiringPassphrase(pwallet) + "\n",
3159                 {
3160                     {"hexstring", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction hex string"},
3161                     {"prevtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "A json array of previous dependent transaction outputs",
3162                         {
3163                             {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
3164                                 {
3165                                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
3166                                     {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
3167                                     {"scriptPubKey", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "script key"},
3168                                     {"redeemScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2SH) redeem script"},
3169                                     {"witnessScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2WSH or P2SH-P2WSH) witness script"},
3170                                     {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The amount spent"},
3171                                 },
3172                             },
3173                         },
3174                     },
3175                     {"sighashtype", RPCArg::Type::STR, /* default */ "ALL", "The signature hash type. Must be one of\n"
3176             "       \"ALL\"\n"
3177             "       \"NONE\"\n"
3178             "       \"SINGLE\"\n"
3179             "       \"ALL|ANYONECANPAY\"\n"
3180             "       \"NONE|ANYONECANPAY\"\n"
3181             "       \"SINGLE|ANYONECANPAY\""},
3182                 },
3183                 RPCResult{
3184             "{\n"
3185             "  \"hex\" : \"value\",                  (string) The hex-encoded raw transaction with signature(s)\n"
3186             "  \"complete\" : true|false,          (boolean) If the transaction has a complete set of signatures\n"
3187             "  \"errors\" : [                      (json array of objects) Script verification errors (if there are any)\n"
3188             "    {\n"
3189             "      \"txid\" : \"hash\",              (string) The hash of the referenced, previous transaction\n"
3190             "      \"vout\" : n,                   (numeric) The index of the output to spent and used as input\n"
3191             "      \"scriptSig\" : \"hex\",          (string) The hex-encoded signature script\n"
3192             "      \"sequence\" : n,               (numeric) Script sequence number\n"
3193             "      \"error\" : \"text\"              (string) Verification or signing error related to the input\n"
3194             "    }\n"
3195             "    ,...\n"
3196             "  ]\n"
3197             "}\n"
3198                 },
3199                 RPCExamples{
3200                     HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"")
3201             + HelpExampleRpc("signrawtransactionwithwallet", "\"myhex\"")
3202                 },
3203             }.ToString());
3204 
3205     RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VSTR}, true);
3206 
3207     CMutableTransaction mtx;
3208     if (!DecodeHexTx(mtx, request.params[0].get_str(), true)) {
3209         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
3210     }
3211 
3212     // Sign the transaction
3213     auto locked_chain = pwallet->chain().lock();
3214     LOCK(pwallet->cs_wallet);
3215     EnsureWalletIsUnlocked(pwallet);
3216 
3217     return SignTransaction(pwallet->chain(), mtx, request.params[1], pwallet, false, request.params[2]);
3218 }
3219 
bumpfee(const JSONRPCRequest & request)3220 static UniValue bumpfee(const JSONRPCRequest& request)
3221 {
3222     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3223     CWallet* const pwallet = wallet.get();
3224 
3225 
3226     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
3227         return NullUniValue;
3228 
3229     if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
3230         throw std::runtime_error(
3231             RPCHelpMan{"bumpfee",
3232                 "\nBumps the fee of an opt-in-RBF transaction T, replacing it with a new transaction B.\n"
3233                 "An opt-in RBF transaction with the given txid must be in the wallet.\n"
3234                 "The command will pay the additional fee by decreasing (or perhaps removing) its change output.\n"
3235                 "If the change output is not big enough to cover the increased fee, the command will currently fail\n"
3236                 "instead of adding new inputs to compensate. (A future implementation could improve this.)\n"
3237                 "The command will fail if the wallet or mempool contains a transaction that spends one of T's outputs.\n"
3238                 "By default, the new fee will be calculated automatically using estimatesmartfee.\n"
3239                 "The user can specify a confirmation target for estimatesmartfee.\n"
3240                 "Alternatively, the user can specify totalFee, or use RPC settxfee to set a higher fee rate.\n"
3241                 "At a minimum, the new fee rate must be high enough to pay an additional new relay fee (incrementalfee\n"
3242                 "returned by getnetworkinfo) to enter the node's mempool.\n",
3243                 {
3244                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The txid to be bumped"},
3245                     {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
3246                         {
3247                             {"confTarget", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks)"},
3248                             {"totalFee", RPCArg::Type::NUM, /* default */ "fallback to 'confTarget'", "Total fee (NOT feerate) to pay, in satoshis.\n"
3249             "                         In rare cases, the actual fee paid might be slightly higher than the specified\n"
3250             "                         totalFee if the tx change output has to be removed because it is too close to\n"
3251             "                         the dust threshold."},
3252                             {"replaceable", RPCArg::Type::BOOL, /* default */ "true", "Whether the new transaction should still be\n"
3253             "                         marked bip-125 replaceable. If true, the sequence numbers in the transaction will\n"
3254             "                         be left unchanged from the original. If false, any input sequence numbers in the\n"
3255             "                         original transaction that were less than 0xfffffffe will be increased to 0xfffffffe\n"
3256             "                         so the new transaction will not be explicitly bip-125 replaceable (though it may\n"
3257             "                         still be replaceable in practice, for example if it has unconfirmed ancestors which\n"
3258             "                         are replaceable)."},
3259                             {"estimate_mode", RPCArg::Type::STR, /* default */ "UNSET", "The fee estimate mode, must be one of:\n"
3260             "         \"UNSET\"\n"
3261             "         \"ECONOMICAL\"\n"
3262             "         \"CONSERVATIVE\""},
3263                         },
3264                         "options"},
3265                 },
3266                 RPCResult{
3267             "{\n"
3268             "  \"txid\":    \"value\",   (string)  The id of the new transaction\n"
3269             "  \"origfee\":  n,         (numeric) Fee of the replaced transaction\n"
3270             "  \"fee\":      n,         (numeric) Fee of the new transaction\n"
3271             "  \"errors\":  [ str... ] (json array of strings) Errors encountered during processing (may be empty)\n"
3272             "}\n"
3273                 },
3274                 RPCExamples{
3275             "\nBump the fee, get the new transaction\'s txid\n" +
3276                     HelpExampleCli("bumpfee", "<txid>")
3277                 },
3278             }.ToString());
3279     }
3280 
3281     RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ});
3282     uint256 hash(ParseHashV(request.params[0], "txid"));
3283 
3284     // optional parameters
3285     CAmount totalFee = 0;
3286     CCoinControl coin_control;
3287     coin_control.m_signal_bip125_rbf = true;
3288     if (!request.params[1].isNull()) {
3289         UniValue options = request.params[1];
3290         RPCTypeCheckObj(options,
3291             {
3292                 {"confTarget", UniValueType(UniValue::VNUM)},
3293                 {"totalFee", UniValueType(UniValue::VNUM)},
3294                 {"replaceable", UniValueType(UniValue::VBOOL)},
3295                 {"estimate_mode", UniValueType(UniValue::VSTR)},
3296             },
3297             true, true);
3298 
3299         if (options.exists("confTarget") && options.exists("totalFee")) {
3300             throw JSONRPCError(RPC_INVALID_PARAMETER, "confTarget and totalFee options should not both be set. Please provide either a confirmation target for fee estimation or an explicit total fee for the transaction.");
3301         } else if (options.exists("confTarget")) { // TODO: alias this to conf_target
3302             coin_control.m_confirm_target = ParseConfirmTarget(options["confTarget"]);
3303         } else if (options.exists("totalFee")) {
3304             totalFee = options["totalFee"].get_int64();
3305             if (totalFee <= 0) {
3306                 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid totalFee %s (must be greater than 0)", FormatMoney(totalFee)));
3307             }
3308         }
3309 
3310         if (options.exists("replaceable")) {
3311             coin_control.m_signal_bip125_rbf = options["replaceable"].get_bool();
3312         }
3313         if (options.exists("estimate_mode")) {
3314             if (!FeeModeFromString(options["estimate_mode"].get_str(), coin_control.m_fee_mode)) {
3315                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
3316             }
3317         }
3318     }
3319 
3320     // Make sure the results are valid at least up to the most recent block
3321     // the user could have gotten from another RPC command prior to now
3322     pwallet->BlockUntilSyncedToCurrentChain();
3323 
3324     auto locked_chain = pwallet->chain().lock();
3325     LOCK(pwallet->cs_wallet);
3326     EnsureWalletIsUnlocked(pwallet);
3327 
3328 
3329     std::vector<std::string> errors;
3330     CAmount old_fee;
3331     CAmount new_fee;
3332     CMutableTransaction mtx;
3333     feebumper::Result res = feebumper::CreateTransaction(pwallet, hash, coin_control, totalFee, errors, old_fee, new_fee, mtx);
3334     if (res != feebumper::Result::OK) {
3335         switch(res) {
3336             case feebumper::Result::INVALID_ADDRESS_OR_KEY:
3337                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, errors[0]);
3338                 break;
3339             case feebumper::Result::INVALID_REQUEST:
3340                 throw JSONRPCError(RPC_INVALID_REQUEST, errors[0]);
3341                 break;
3342             case feebumper::Result::INVALID_PARAMETER:
3343                 throw JSONRPCError(RPC_INVALID_PARAMETER, errors[0]);
3344                 break;
3345             case feebumper::Result::WALLET_ERROR:
3346                 throw JSONRPCError(RPC_WALLET_ERROR, errors[0]);
3347                 break;
3348             default:
3349                 throw JSONRPCError(RPC_MISC_ERROR, errors[0]);
3350                 break;
3351         }
3352     }
3353 
3354     // sign bumped transaction
3355     if (!feebumper::SignTransaction(pwallet, mtx)) {
3356         throw JSONRPCError(RPC_WALLET_ERROR, "Can't sign transaction.");
3357     }
3358     // commit the bumped transaction
3359     uint256 txid;
3360     if (feebumper::CommitTransaction(pwallet, hash, std::move(mtx), errors, txid) != feebumper::Result::OK) {
3361         throw JSONRPCError(RPC_WALLET_ERROR, errors[0]);
3362     }
3363     UniValue result(UniValue::VOBJ);
3364     result.pushKV("txid", txid.GetHex());
3365     result.pushKV("origfee", ValueFromAmount(old_fee));
3366     result.pushKV("fee", ValueFromAmount(new_fee));
3367     UniValue result_errors(UniValue::VARR);
3368     for (const std::string& error : errors) {
3369         result_errors.push_back(error);
3370     }
3371     result.pushKV("errors", result_errors);
3372 
3373     return result;
3374 }
3375 
generate(const JSONRPCRequest & request)3376 UniValue generate(const JSONRPCRequest& request)
3377 {
3378     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3379     CWallet* const pwallet = wallet.get();
3380 
3381 
3382     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3383         return NullUniValue;
3384     }
3385 
3386     if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
3387         throw std::runtime_error(
3388             RPCHelpMan{"generate",
3389                 "\nMine up to nblocks blocks immediately (before the RPC call returns) to an address in the wallet.\n",
3390                 {
3391                     {"nblocks", RPCArg::Type::NUM, RPCArg::Optional::NO, "How many blocks are generated immediately."},
3392                     {"maxtries", RPCArg::Type::NUM, /* default */ "1000000", "How many iterations to try."},
3393                 },
3394                 RPCResult{
3395             "[ blockhashes ]     (array) hashes of blocks generated\n"
3396                 },
3397                 RPCExamples{
3398             "\nGenerate 11 blocks\n"
3399             + HelpExampleCli("generate", "11")
3400                 },
3401             }.ToString());
3402     }
3403 
3404     if (!IsDeprecatedRPCEnabled("generate")) {
3405         throw JSONRPCError(RPC_METHOD_DEPRECATED, "The wallet generate rpc method is deprecated and will be fully removed in v0.19. "
3406             "To use generate in v0.18, restart litecoind with -deprecatedrpc=generate.\n"
3407             "Clients should transition to using the node rpc method generatetoaddress\n");
3408     }
3409 
3410     int num_generate = request.params[0].get_int();
3411     uint64_t max_tries = 1000000;
3412     if (!request.params[1].isNull()) {
3413         max_tries = request.params[1].get_int();
3414     }
3415 
3416     std::shared_ptr<CReserveScript> coinbase_script;
3417     pwallet->GetScriptForMining(coinbase_script);
3418 
3419     // If the keypool is exhausted, no script is returned at all.  Catch this.
3420     if (!coinbase_script) {
3421         throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
3422     }
3423 
3424     //throw an error if no script was provided
3425     if (coinbase_script->reserveScript.empty()) {
3426         throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available");
3427     }
3428 
3429     return generateBlocks(coinbase_script, num_generate, max_tries, true);
3430 }
3431 
rescanblockchain(const JSONRPCRequest & request)3432 UniValue rescanblockchain(const JSONRPCRequest& request)
3433 {
3434     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3435     CWallet* const pwallet = wallet.get();
3436 
3437     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3438         return NullUniValue;
3439     }
3440 
3441     if (request.fHelp || request.params.size() > 2) {
3442         throw std::runtime_error(
3443             RPCHelpMan{"rescanblockchain",
3444                 "\nRescan the local blockchain for wallet related transactions.\n",
3445                 {
3446                     {"start_height", RPCArg::Type::NUM, /* default */ "0", "block height where the rescan should start"},
3447                     {"stop_height", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "the last block height that should be scanned. If none is provided it will rescan up to the tip at return time of this call."},
3448                 },
3449                 RPCResult{
3450             "{\n"
3451             "  \"start_height\"     (numeric) The block height where the rescan started (the requested height or 0)\n"
3452             "  \"stop_height\"      (numeric) The height of the last rescanned block. May be null in rare cases if there was a reorg and the call didn't scan any blocks because they were already scanned in the background.\n"
3453             "}\n"
3454                 },
3455                 RPCExamples{
3456                     HelpExampleCli("rescanblockchain", "100000 120000")
3457             + HelpExampleRpc("rescanblockchain", "100000, 120000")
3458                 },
3459             }.ToString());
3460     }
3461 
3462     WalletRescanReserver reserver(pwallet);
3463     if (!reserver.reserve()) {
3464         throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
3465     }
3466 
3467     int start_height = 0;
3468     uint256 start_block, stop_block;
3469     {
3470         auto locked_chain = pwallet->chain().lock();
3471         Optional<int> tip_height = locked_chain->getHeight();
3472 
3473         if (!request.params[0].isNull()) {
3474             start_height = request.params[0].get_int();
3475             if (start_height < 0 || !tip_height || start_height > *tip_height) {
3476                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid start_height");
3477             }
3478         }
3479 
3480         Optional<int> stop_height;
3481         if (!request.params[1].isNull()) {
3482             stop_height = request.params[1].get_int();
3483             if (*stop_height < 0 || !tip_height || *stop_height > *tip_height) {
3484                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid stop_height");
3485             }
3486             else if (*stop_height < start_height) {
3487                 throw JSONRPCError(RPC_INVALID_PARAMETER, "stop_height must be greater than start_height");
3488             }
3489         }
3490 
3491         // We can't rescan beyond non-pruned blocks, stop and throw an error
3492         if (locked_chain->findPruned(start_height, stop_height)) {
3493             throw JSONRPCError(RPC_MISC_ERROR, "Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height.");
3494         }
3495 
3496         if (tip_height) {
3497             start_block = locked_chain->getBlockHash(start_height);
3498             // If called with a stop_height, set the stop_height here to
3499             // trigger a rescan to that height.
3500             // If called without a stop height, leave stop_height as null here
3501             // so rescan continues to the tip (even if the tip advances during
3502             // rescan).
3503             if (stop_height) {
3504                 stop_block = locked_chain->getBlockHash(*stop_height);
3505             }
3506         }
3507     }
3508 
3509     CWallet::ScanResult result =
3510         pwallet->ScanForWalletTransactions(start_block, stop_block, reserver, true /* fUpdate */);
3511     switch (result.status) {
3512     case CWallet::ScanResult::SUCCESS:
3513         break;
3514     case CWallet::ScanResult::FAILURE:
3515         throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corrupted data files.");
3516     case CWallet::ScanResult::USER_ABORT:
3517         throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");
3518         // no default case, so the compiler can warn about missing cases
3519     }
3520     UniValue response(UniValue::VOBJ);
3521     response.pushKV("start_height", start_height);
3522     response.pushKV("stop_height", result.last_scanned_height ? *result.last_scanned_height : UniValue());
3523     return response;
3524 }
3525 
3526 class DescribeWalletAddressVisitor : public boost::static_visitor<UniValue>
3527 {
3528 public:
3529     CWallet * const pwallet;
3530 
ProcessSubScript(const CScript & subscript,UniValue & obj) const3531     void ProcessSubScript(const CScript& subscript, UniValue& obj) const
3532     {
3533         // Always present: script type and redeemscript
3534         std::vector<std::vector<unsigned char>> solutions_data;
3535         txnouttype which_type = Solver(subscript, solutions_data);
3536         obj.pushKV("script", GetTxnOutputType(which_type));
3537         obj.pushKV("hex", HexStr(subscript.begin(), subscript.end()));
3538 
3539         CTxDestination embedded;
3540         if (ExtractDestination(subscript, embedded)) {
3541             // Only when the script corresponds to an address.
3542             UniValue subobj(UniValue::VOBJ);
3543             UniValue detail = DescribeAddress(embedded);
3544             subobj.pushKVs(detail);
3545             UniValue wallet_detail = boost::apply_visitor(*this, embedded);
3546             subobj.pushKVs(wallet_detail);
3547             subobj.pushKV("address", EncodeDestination(embedded));
3548             subobj.pushKV("scriptPubKey", HexStr(subscript.begin(), subscript.end()));
3549             // Always report the pubkey at the top level, so that `getnewaddress()['pubkey']` always works.
3550             if (subobj.exists("pubkey")) obj.pushKV("pubkey", subobj["pubkey"]);
3551             obj.pushKV("embedded", std::move(subobj));
3552         } else if (which_type == TX_MULTISIG) {
3553             // Also report some information on multisig scripts (which do not have a corresponding address).
3554             // TODO: abstract out the common functionality between this logic and ExtractDestinations.
3555             obj.pushKV("sigsrequired", solutions_data[0][0]);
3556             UniValue pubkeys(UniValue::VARR);
3557             for (size_t i = 1; i < solutions_data.size() - 1; ++i) {
3558                 CPubKey key(solutions_data[i].begin(), solutions_data[i].end());
3559                 pubkeys.push_back(HexStr(key.begin(), key.end()));
3560             }
3561             obj.pushKV("pubkeys", std::move(pubkeys));
3562         }
3563     }
3564 
DescribeWalletAddressVisitor(CWallet * _pwallet)3565     explicit DescribeWalletAddressVisitor(CWallet* _pwallet) : pwallet(_pwallet) {}
3566 
operator ()(const CNoDestination & dest) const3567     UniValue operator()(const CNoDestination& dest) const { return UniValue(UniValue::VOBJ); }
3568 
operator ()(const CKeyID & keyID) const3569     UniValue operator()(const CKeyID& keyID) const
3570     {
3571         UniValue obj(UniValue::VOBJ);
3572         CPubKey vchPubKey;
3573         if (pwallet && pwallet->GetPubKey(keyID, vchPubKey)) {
3574             obj.pushKV("pubkey", HexStr(vchPubKey));
3575             obj.pushKV("iscompressed", vchPubKey.IsCompressed());
3576         }
3577         return obj;
3578     }
3579 
operator ()(const CScriptID & scriptID) const3580     UniValue operator()(const CScriptID& scriptID) const
3581     {
3582         UniValue obj(UniValue::VOBJ);
3583         CScript subscript;
3584         if (pwallet && pwallet->GetCScript(scriptID, subscript)) {
3585             ProcessSubScript(subscript, obj);
3586         }
3587         return obj;
3588     }
3589 
operator ()(const WitnessV0KeyHash & id) const3590     UniValue operator()(const WitnessV0KeyHash& id) const
3591     {
3592         UniValue obj(UniValue::VOBJ);
3593         CPubKey pubkey;
3594         if (pwallet && pwallet->GetPubKey(CKeyID(id), pubkey)) {
3595             obj.pushKV("pubkey", HexStr(pubkey));
3596         }
3597         return obj;
3598     }
3599 
operator ()(const WitnessV0ScriptHash & id) const3600     UniValue operator()(const WitnessV0ScriptHash& id) const
3601     {
3602         UniValue obj(UniValue::VOBJ);
3603         CScript subscript;
3604         CRIPEMD160 hasher;
3605         uint160 hash;
3606         hasher.Write(id.begin(), 32).Finalize(hash.begin());
3607         if (pwallet && pwallet->GetCScript(CScriptID(hash), subscript)) {
3608             ProcessSubScript(subscript, obj);
3609         }
3610         return obj;
3611     }
3612 
operator ()(const WitnessUnknown & id) const3613     UniValue operator()(const WitnessUnknown& id) const { return UniValue(UniValue::VOBJ); }
3614 };
3615 
DescribeWalletAddress(CWallet * pwallet,const CTxDestination & dest)3616 static UniValue DescribeWalletAddress(CWallet* pwallet, const CTxDestination& dest)
3617 {
3618     UniValue ret(UniValue::VOBJ);
3619     UniValue detail = DescribeAddress(dest);
3620     ret.pushKVs(detail);
3621     ret.pushKVs(boost::apply_visitor(DescribeWalletAddressVisitor(pwallet), dest));
3622     return ret;
3623 }
3624 
3625 /** Convert CAddressBookData to JSON record.  */
AddressBookDataToJSON(const CAddressBookData & data,const bool verbose)3626 static UniValue AddressBookDataToJSON(const CAddressBookData& data, const bool verbose)
3627 {
3628     UniValue ret(UniValue::VOBJ);
3629     if (verbose) {
3630         ret.pushKV("name", data.name);
3631     }
3632     ret.pushKV("purpose", data.purpose);
3633     return ret;
3634 }
3635 
getaddressinfo(const JSONRPCRequest & request)3636 UniValue getaddressinfo(const JSONRPCRequest& request)
3637 {
3638     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3639     CWallet* const pwallet = wallet.get();
3640 
3641     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3642         return NullUniValue;
3643     }
3644 
3645     if (request.fHelp || request.params.size() != 1) {
3646         throw std::runtime_error(
3647             RPCHelpMan{"getaddressinfo",
3648                 "\nReturn information about the given litecoin address. Some information requires the address\n"
3649                 "to be in the wallet.\n",
3650                 {
3651                     {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The litecoin address to get the information of."},
3652                 },
3653                 RPCResult{
3654             "{\n"
3655             "  \"address\" : \"address\",        (string) The litecoin address validated\n"
3656             "  \"scriptPubKey\" : \"hex\",       (string) The hex-encoded scriptPubKey generated by the address\n"
3657             "  \"ismine\" : true|false,        (boolean) If the address is yours or not\n"
3658             "  \"iswatchonly\" : true|false,   (boolean) If the address is watchonly\n"
3659             "  \"solvable\" : true|false,      (boolean) Whether we know how to spend coins sent to this address, ignoring the possible lack of private keys\n"
3660             "  \"desc\" : \"desc\",            (string, optional) A descriptor for spending coins sent to this address (only when solvable)\n"
3661             "  \"isscript\" : true|false,      (boolean) If the key is a script\n"
3662             "  \"ischange\" : true|false,      (boolean) If the address was used for change output\n"
3663             "  \"iswitness\" : true|false,     (boolean) If the address is a witness address\n"
3664             "  \"witness_version\" : version   (numeric, optional) The version number of the witness program\n"
3665             "  \"witness_program\" : \"hex\"     (string, optional) The hex value of the witness program\n"
3666             "  \"script\" : \"type\"             (string, optional) The output script type. Only if \"isscript\" is true and the redeemscript is known. Possible types: nonstandard, pubkey, pubkeyhash, scripthash, multisig, nulldata, witness_v0_keyhash, witness_v0_scripthash, witness_unknown\n"
3667             "  \"hex\" : \"hex\",                (string, optional) The redeemscript for the p2sh address\n"
3668             "  \"pubkeys\"                     (string, optional) Array of pubkeys associated with the known redeemscript (only if \"script\" is \"multisig\")\n"
3669             "    [\n"
3670             "      \"pubkey\"\n"
3671             "      ,...\n"
3672             "    ]\n"
3673             "  \"sigsrequired\" : xxxxx        (numeric, optional) Number of signatures required to spend multisig output (only if \"script\" is \"multisig\")\n"
3674             "  \"pubkey\" : \"publickeyhex\",    (string, optional) The hex value of the raw public key, for single-key addresses (possibly embedded in P2SH or P2WSH)\n"
3675             "  \"embedded\" : {...},           (object, optional) Information about the address embedded in P2SH or P2WSH, if relevant and known. It includes all getaddressinfo output fields for the embedded address, excluding metadata (\"timestamp\", \"hdkeypath\", \"hdseedid\") and relation to the wallet (\"ismine\", \"iswatchonly\").\n"
3676             "  \"iscompressed\" : true|false,  (boolean, optional) If the pubkey is compressed\n"
3677             "  \"label\" :  \"label\"         (string) The label associated with the address, \"\" is the default label\n"
3678             "  \"timestamp\" : timestamp,      (number, optional) The creation time of the key if available in seconds since epoch (Jan 1 1970 GMT)\n"
3679             "  \"hdkeypath\" : \"keypath\"       (string, optional) The HD keypath if the key is HD and available\n"
3680             "  \"hdseedid\" : \"<hash160>\"      (string, optional) The Hash160 of the HD seed\n"
3681             "  \"hdmasterfingerprint\" : \"<hash160>\" (string, optional) The fingperint of the master key.\n"
3682             "  \"labels\"                      (object) Array of labels associated with the address.\n"
3683             "    [\n"
3684             "      { (json object of label data)\n"
3685             "        \"name\": \"labelname\" (string) The label\n"
3686             "        \"purpose\": \"string\" (string) Purpose of address (\"send\" for sending address, \"receive\" for receiving address)\n"
3687             "      },...\n"
3688             "    ]\n"
3689             "}\n"
3690                 },
3691                 RPCExamples{
3692                     HelpExampleCli("getaddressinfo", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
3693             + HelpExampleRpc("getaddressinfo", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
3694                 },
3695             }.ToString());
3696     }
3697 
3698     LOCK(pwallet->cs_wallet);
3699 
3700     UniValue ret(UniValue::VOBJ);
3701     CTxDestination dest = DecodeDestination(request.params[0].get_str());
3702 
3703     // Make sure the destination is valid
3704     if (!IsValidDestination(dest)) {
3705         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
3706     }
3707 
3708     std::string currentAddress = EncodeDestination(dest);
3709     ret.pushKV("address", currentAddress);
3710 
3711     CScript scriptPubKey = GetScriptForDestination(dest);
3712     ret.pushKV("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end()));
3713 
3714     isminetype mine = IsMine(*pwallet, dest);
3715     ret.pushKV("ismine", bool(mine & ISMINE_SPENDABLE));
3716     bool solvable = IsSolvable(*pwallet, scriptPubKey);
3717     ret.pushKV("solvable", solvable);
3718     if (solvable) {
3719        ret.pushKV("desc", InferDescriptor(scriptPubKey, *pwallet)->ToString());
3720     }
3721     ret.pushKV("iswatchonly", bool(mine & ISMINE_WATCH_ONLY));
3722     UniValue detail = DescribeWalletAddress(pwallet, dest);
3723     ret.pushKVs(detail);
3724     if (pwallet->mapAddressBook.count(dest)) {
3725         ret.pushKV("label", pwallet->mapAddressBook[dest].name);
3726     }
3727     ret.pushKV("ischange", pwallet->IsChange(scriptPubKey));
3728     const CKeyMetadata* meta = nullptr;
3729     CKeyID key_id = GetKeyForDestination(*pwallet, dest);
3730     if (!key_id.IsNull()) {
3731         auto it = pwallet->mapKeyMetadata.find(key_id);
3732         if (it != pwallet->mapKeyMetadata.end()) {
3733             meta = &it->second;
3734         }
3735     }
3736     if (!meta) {
3737         auto it = pwallet->m_script_metadata.find(CScriptID(scriptPubKey));
3738         if (it != pwallet->m_script_metadata.end()) {
3739             meta = &it->second;
3740         }
3741     }
3742     if (meta) {
3743         ret.pushKV("timestamp", meta->nCreateTime);
3744         if (meta->has_key_origin) {
3745             ret.pushKV("hdkeypath", WriteHDKeypath(meta->key_origin.path));
3746             ret.pushKV("hdseedid", meta->hd_seed_id.GetHex());
3747             ret.pushKV("hdmasterfingerprint", HexStr(meta->key_origin.fingerprint, meta->key_origin.fingerprint + 4));
3748         }
3749     }
3750 
3751     // Currently only one label can be associated with an address, return an array
3752     // so the API remains stable if we allow multiple labels to be associated with
3753     // an address.
3754     UniValue labels(UniValue::VARR);
3755     std::map<CTxDestination, CAddressBookData>::iterator mi = pwallet->mapAddressBook.find(dest);
3756     if (mi != pwallet->mapAddressBook.end()) {
3757         labels.push_back(AddressBookDataToJSON(mi->second, true));
3758     }
3759     ret.pushKV("labels", std::move(labels));
3760 
3761     return ret;
3762 }
3763 
getaddressesbylabel(const JSONRPCRequest & request)3764 static UniValue getaddressesbylabel(const JSONRPCRequest& request)
3765 {
3766     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3767     CWallet* const pwallet = wallet.get();
3768 
3769     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3770         return NullUniValue;
3771     }
3772 
3773     if (request.fHelp || request.params.size() != 1)
3774         throw std::runtime_error(
3775             RPCHelpMan{"getaddressesbylabel",
3776                 "\nReturns the list of addresses assigned the specified label.\n",
3777                 {
3778                     {"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The label."},
3779                 },
3780                 RPCResult{
3781             "{ (json object with addresses as keys)\n"
3782             "  \"address\": { (json object with information about address)\n"
3783             "    \"purpose\": \"string\" (string)  Purpose of address (\"send\" for sending address, \"receive\" for receiving address)\n"
3784             "  },...\n"
3785             "}\n"
3786                 },
3787                 RPCExamples{
3788                     HelpExampleCli("getaddressesbylabel", "\"tabby\"")
3789             + HelpExampleRpc("getaddressesbylabel", "\"tabby\"")
3790                 },
3791             }.ToString());
3792 
3793     LOCK(pwallet->cs_wallet);
3794 
3795     std::string label = LabelFromValue(request.params[0]);
3796 
3797     // Find all addresses that have the given label
3798     UniValue ret(UniValue::VOBJ);
3799     for (const std::pair<const CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
3800         if (item.second.name == label) {
3801             ret.pushKV(EncodeDestination(item.first), AddressBookDataToJSON(item.second, false));
3802         }
3803     }
3804 
3805     if (ret.empty()) {
3806         throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, std::string("No addresses with label " + label));
3807     }
3808 
3809     return ret;
3810 }
3811 
listlabels(const JSONRPCRequest & request)3812 static UniValue listlabels(const JSONRPCRequest& request)
3813 {
3814     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3815     CWallet* const pwallet = wallet.get();
3816 
3817     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3818         return NullUniValue;
3819     }
3820 
3821     if (request.fHelp || request.params.size() > 1)
3822         throw std::runtime_error(
3823             RPCHelpMan{"listlabels",
3824                 "\nReturns the list of all labels, or labels that are assigned to addresses with a specific purpose.\n",
3825                 {
3826                     {"purpose", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Address purpose to list labels for ('send','receive'). An empty string is the same as not providing this argument."},
3827                 },
3828                 RPCResult{
3829             "[               (json array of string)\n"
3830             "  \"label\",      (string) Label name\n"
3831             "  ...\n"
3832             "]\n"
3833                 },
3834                 RPCExamples{
3835             "\nList all labels\n"
3836             + HelpExampleCli("listlabels", "") +
3837             "\nList labels that have receiving addresses\n"
3838             + HelpExampleCli("listlabels", "receive") +
3839             "\nList labels that have sending addresses\n"
3840             + HelpExampleCli("listlabels", "send") +
3841             "\nAs a JSON-RPC call\n"
3842             + HelpExampleRpc("listlabels", "receive")
3843                 },
3844             }.ToString());
3845 
3846     LOCK(pwallet->cs_wallet);
3847 
3848     std::string purpose;
3849     if (!request.params[0].isNull()) {
3850         purpose = request.params[0].get_str();
3851     }
3852 
3853     // Add to a set to sort by label name, then insert into Univalue array
3854     std::set<std::string> label_set;
3855     for (const std::pair<const CTxDestination, CAddressBookData>& entry : pwallet->mapAddressBook) {
3856         if (purpose.empty() || entry.second.purpose == purpose) {
3857             label_set.insert(entry.second.name);
3858         }
3859     }
3860 
3861     UniValue ret(UniValue::VARR);
3862     for (const std::string& name : label_set) {
3863         ret.push_back(name);
3864     }
3865 
3866     return ret;
3867 }
3868 
sethdseed(const JSONRPCRequest & request)3869 UniValue sethdseed(const JSONRPCRequest& request)
3870 {
3871     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3872     CWallet* const pwallet = wallet.get();
3873 
3874     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3875         return NullUniValue;
3876     }
3877 
3878     if (request.fHelp || request.params.size() > 2) {
3879         throw std::runtime_error(
3880             RPCHelpMan{"sethdseed",
3881                 "\nSet or generate a new HD wallet seed. Non-HD wallets will not be upgraded to being a HD wallet. Wallets that are already\n"
3882                 "HD will have a new HD seed set so that new keys added to the keypool will be derived from this new seed.\n"
3883                 "\nNote that you will need to MAKE A NEW BACKUP of your wallet after setting the HD wallet seed." +
3884                     HelpRequiringPassphrase(pwallet) + "\n",
3885                 {
3886                     {"newkeypool", RPCArg::Type::BOOL, /* default */ "true", "Whether to flush old unused addresses, including change addresses, from the keypool and regenerate it.\n"
3887             "                             If true, the next address from getnewaddress and change address from getrawchangeaddress will be from this new seed.\n"
3888             "                             If false, addresses (including change addresses if the wallet already had HD Chain Split enabled) from the existing\n"
3889             "                             keypool will be used until it has been depleted."},
3890                     {"seed", RPCArg::Type::STR, /* default */ "random seed", "The WIF private key to use as the new HD seed.\n"
3891             "                             The seed value can be retrieved using the dumpwallet command. It is the private key marked hdseed=1"},
3892                 },
3893                 RPCResults{},
3894                 RPCExamples{
3895                     HelpExampleCli("sethdseed", "")
3896             + HelpExampleCli("sethdseed", "false")
3897             + HelpExampleCli("sethdseed", "true \"wifkey\"")
3898             + HelpExampleRpc("sethdseed", "true, \"wifkey\"")
3899                 },
3900             }.ToString());
3901     }
3902 
3903     if (IsInitialBlockDownload()) {
3904         throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Cannot set a new HD seed while still in Initial Block Download");
3905     }
3906 
3907     if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
3908         throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed to a wallet with private keys disabled");
3909     }
3910 
3911     auto locked_chain = pwallet->chain().lock();
3912     LOCK(pwallet->cs_wallet);
3913 
3914     // Do not do anything to non-HD wallets
3915     if (!pwallet->CanSupportFeature(FEATURE_HD)) {
3916         throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed on a non-HD wallet. Start with -upgradewallet in order to upgrade a non-HD wallet to HD");
3917     }
3918 
3919     EnsureWalletIsUnlocked(pwallet);
3920 
3921     bool flush_key_pool = true;
3922     if (!request.params[0].isNull()) {
3923         flush_key_pool = request.params[0].get_bool();
3924     }
3925 
3926     CPubKey master_pub_key;
3927     if (request.params[1].isNull()) {
3928         master_pub_key = pwallet->GenerateNewSeed();
3929     } else {
3930         CKey key = DecodeSecret(request.params[1].get_str());
3931         if (!key.IsValid()) {
3932             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
3933         }
3934 
3935         if (HaveKey(*pwallet, key)) {
3936             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Already have this key (either as an HD seed or as a loose private key)");
3937         }
3938 
3939         master_pub_key = pwallet->DeriveNewSeed(key);
3940     }
3941 
3942     pwallet->SetHDSeed(master_pub_key);
3943     if (flush_key_pool) pwallet->NewKeyPool();
3944 
3945     return NullUniValue;
3946 }
3947 
AddKeypathToMap(const CWallet * pwallet,const CKeyID & keyID,std::map<CPubKey,KeyOriginInfo> & hd_keypaths)3948 void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map<CPubKey, KeyOriginInfo>& hd_keypaths)
3949 {
3950     CPubKey vchPubKey;
3951     if (!pwallet->GetPubKey(keyID, vchPubKey)) {
3952         return;
3953     }
3954     KeyOriginInfo info;
3955     if (!pwallet->GetKeyOrigin(keyID, info)) {
3956         throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal keypath is broken");
3957     }
3958     hd_keypaths.emplace(vchPubKey, std::move(info));
3959 }
3960 
walletprocesspsbt(const JSONRPCRequest & request)3961 UniValue walletprocesspsbt(const JSONRPCRequest& request)
3962 {
3963     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3964     CWallet* const pwallet = wallet.get();
3965 
3966     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3967         return NullUniValue;
3968     }
3969 
3970     if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
3971         throw std::runtime_error(
3972             RPCHelpMan{"walletprocesspsbt",
3973                 "\nUpdate a PSBT with input information from our wallet and then sign inputs\n"
3974                 "that we can sign for." +
3975                     HelpRequiringPassphrase(pwallet) + "\n",
3976                 {
3977                     {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction base64 string"},
3978                     {"sign", RPCArg::Type::BOOL, /* default */ "true", "Also sign the transaction when updating"},
3979                     {"sighashtype", RPCArg::Type::STR, /* default */ "ALL", "The signature hash type to sign with if not specified by the PSBT. Must be one of\n"
3980             "       \"ALL\"\n"
3981             "       \"NONE\"\n"
3982             "       \"SINGLE\"\n"
3983             "       \"ALL|ANYONECANPAY\"\n"
3984             "       \"NONE|ANYONECANPAY\"\n"
3985             "       \"SINGLE|ANYONECANPAY\""},
3986                     {"bip32derivs", RPCArg::Type::BOOL, /* default */ "false", "If true, includes the BIP 32 derivation paths for public keys if we know them"},
3987                 },
3988                 RPCResult{
3989             "{\n"
3990             "  \"psbt\" : \"value\",          (string) The base64-encoded partially signed transaction\n"
3991             "  \"complete\" : true|false,   (boolean) If the transaction has a complete set of signatures\n"
3992             "  ]\n"
3993             "}\n"
3994                 },
3995                 RPCExamples{
3996                     HelpExampleCli("walletprocesspsbt", "\"psbt\"")
3997                 },
3998             }.ToString());
3999 
4000     RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VSTR});
4001 
4002     // Unserialize the transaction
4003     PartiallySignedTransaction psbtx;
4004     std::string error;
4005     if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) {
4006         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
4007     }
4008 
4009     // Get the sighash type
4010     int nHashType = ParseSighashString(request.params[2]);
4011 
4012     // Fill transaction with our data and also sign
4013     bool sign = request.params[1].isNull() ? true : request.params[1].get_bool();
4014     bool bip32derivs = request.params[3].isNull() ? false : request.params[3].get_bool();
4015     bool complete = true;
4016     const TransactionError err = FillPSBT(pwallet, psbtx, complete, nHashType, sign, bip32derivs);
4017     if (err != TransactionError::OK) {
4018         throw JSONRPCTransactionError(err);
4019     }
4020 
4021     UniValue result(UniValue::VOBJ);
4022     CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
4023     ssTx << psbtx;
4024     result.pushKV("psbt", EncodeBase64(ssTx.str()));
4025     result.pushKV("complete", complete);
4026 
4027     return result;
4028 }
4029 
walletcreatefundedpsbt(const JSONRPCRequest & request)4030 UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
4031 {
4032     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
4033     CWallet* const pwallet = wallet.get();
4034 
4035     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
4036         return NullUniValue;
4037     }
4038 
4039     if (request.fHelp || request.params.size() < 2 || request.params.size() > 5)
4040         throw std::runtime_error(
4041             RPCHelpMan{"walletcreatefundedpsbt",
4042                 "\nCreates and funds a transaction in the Partially Signed Transaction format. Inputs will be added if supplied inputs are not enough\n"
4043                 "Implements the Creator and Updater roles.\n",
4044                 {
4045                     {"inputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "A json array of json objects",
4046                         {
4047                             {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
4048                                 {
4049                                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
4050                                     {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
4051                                     {"sequence", RPCArg::Type::NUM, RPCArg::Optional::NO, "The sequence number"},
4052                                 },
4053                             },
4054                         },
4055                         },
4056                     {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "a json array with outputs (key-value pairs), where none of the keys are duplicated.\n"
4057                             "That is, each address can only appear once and there can only be one 'data' object.\n"
4058                             "For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n"
4059                             "                             accepted as second parameter.",
4060                         {
4061                             {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
4062                                 {
4063                                     {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the litecoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + ""},
4064                                 },
4065                                 },
4066                             {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
4067                                 {
4068                                     {"data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A key-value pair. The key must be \"data\", the value is hex-encoded data"},
4069                                 },
4070                             },
4071                         },
4072                     },
4073                     {"locktime", RPCArg::Type::NUM, /* default */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"},
4074                     {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
4075                         {
4076                             {"changeAddress", RPCArg::Type::STR_HEX, /* default */ "pool address", "The litecoin address to receive the change"},
4077                             {"changePosition", RPCArg::Type::NUM, /* default */ "random", "The index of the change output"},
4078                             {"change_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
4079                             {"includeWatching", RPCArg::Type::BOOL, /* default */ "false", "Also select inputs which are watch only"},
4080                             {"lockUnspents", RPCArg::Type::BOOL, /* default */ "false", "Lock selected unspent outputs"},
4081                             {"feeRate", RPCArg::Type::AMOUNT, /* default */ "not set: makes wallet determine the fee", "Set a specific fee rate in " + CURRENCY_UNIT + "/kB"},
4082                             {"subtractFeeFromOutputs", RPCArg::Type::ARR, /* default */ "empty array", "A json array of integers.\n"
4083                             "                              The fee will be equally deducted from the amount of each specified output.\n"
4084                             "                              Those recipients will receive less litecoins than you enter in their corresponding amount field.\n"
4085                             "                              If no outputs are specified here, the sender pays the fee.",
4086                                 {
4087                                     {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
4088                                 },
4089                             },
4090                             {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n"
4091                             "                              Allows this transaction to be replaced by a transaction with higher fees"},
4092                             {"conf_target", RPCArg::Type::NUM, /* default */ "Fallback to wallet's confirmation target", "Confirmation target (in blocks)"},
4093                             {"estimate_mode", RPCArg::Type::STR, /* default */ "UNSET", "The fee estimate mode, must be one of:\n"
4094                             "         \"UNSET\"\n"
4095                             "         \"ECONOMICAL\"\n"
4096                             "         \"CONSERVATIVE\""},
4097                         },
4098                         "options"},
4099                     {"bip32derivs", RPCArg::Type::BOOL, /* default */ "false", "If true, includes the BIP 32 derivation paths for public keys if we know them"},
4100                 },
4101                 RPCResult{
4102                             "{\n"
4103                             "  \"psbt\": \"value\",        (string)  The resulting raw transaction (base64-encoded string)\n"
4104                             "  \"fee\":       n,         (numeric) Fee in " + CURRENCY_UNIT + " the resulting transaction pays\n"
4105                             "  \"changepos\": n          (numeric) The position of the added change output, or -1\n"
4106                             "}\n"
4107                                 },
4108                                 RPCExamples{
4109                             "\nCreate a transaction with no inputs\n"
4110                             + HelpExampleCli("walletcreatefundedpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
4111                                 },
4112                             }.ToString());
4113 
4114     RPCTypeCheck(request.params, {
4115         UniValue::VARR,
4116         UniValueType(), // ARR or OBJ, checked later
4117         UniValue::VNUM,
4118         UniValue::VOBJ,
4119         UniValue::VBOOL
4120         }, true
4121     );
4122 
4123     CAmount fee;
4124     int change_position;
4125     bool rbf = pwallet->m_signal_rbf;
4126     const UniValue &replaceable_arg = request.params[3]["replaceable"];
4127     if (!replaceable_arg.isNull()) {
4128         RPCTypeCheckArgument(replaceable_arg, UniValue::VBOOL);
4129         rbf = replaceable_arg.isTrue();
4130     }
4131     CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf);
4132     FundTransaction(pwallet, rawTx, fee, change_position, request.params[3]);
4133 
4134     // Make a blank psbt
4135     PartiallySignedTransaction psbtx(rawTx);
4136 
4137     // Fill transaction with out data but don't sign
4138     bool bip32derivs = request.params[4].isNull() ? false : request.params[4].get_bool();
4139     bool complete = true;
4140     const TransactionError err = FillPSBT(pwallet, psbtx, complete, 1, false, bip32derivs);
4141     if (err != TransactionError::OK) {
4142         throw JSONRPCTransactionError(err);
4143     }
4144 
4145     // Serialize the PSBT
4146     CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
4147     ssTx << psbtx;
4148 
4149     UniValue result(UniValue::VOBJ);
4150     result.pushKV("psbt", EncodeBase64(ssTx.str()));
4151     result.pushKV("fee", ValueFromAmount(fee));
4152     result.pushKV("changepos", change_position);
4153     return result;
4154 }
4155 
4156 UniValue abortrescan(const JSONRPCRequest& request); // in rpcdump.cpp
4157 UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp
4158 UniValue importprivkey(const JSONRPCRequest& request);
4159 UniValue importaddress(const JSONRPCRequest& request);
4160 UniValue importpubkey(const JSONRPCRequest& request);
4161 UniValue dumpwallet(const JSONRPCRequest& request);
4162 UniValue importwallet(const JSONRPCRequest& request);
4163 UniValue importprunedfunds(const JSONRPCRequest& request);
4164 UniValue removeprunedfunds(const JSONRPCRequest& request);
4165 UniValue importmulti(const JSONRPCRequest& request);
4166 
4167 // clang-format off
4168 static const CRPCCommand commands[] =
4169 { //  category              name                                actor (function)                argNames
4170     //  --------------------- ------------------------          -----------------------         ----------
4171     { "generating",         "generate",                         &generate,                      {"nblocks","maxtries"} },
4172     { "hidden",             "resendwallettransactions",         &resendwallettransactions,      {} },
4173     { "rawtransactions",    "fundrawtransaction",               &fundrawtransaction,            {"hexstring","options","iswitness"} },
4174     { "wallet",             "abandontransaction",               &abandontransaction,            {"txid"} },
4175     { "wallet",             "abortrescan",                      &abortrescan,                   {} },
4176     { "wallet",             "addmultisigaddress",               &addmultisigaddress,            {"nrequired","keys","label","address_type"} },
4177     { "wallet",             "backupwallet",                     &backupwallet,                  {"destination"} },
4178     { "wallet",             "bumpfee",                          &bumpfee,                       {"txid", "options"} },
4179     { "wallet",             "createwallet",                     &createwallet,                  {"wallet_name", "disable_private_keys", "blank"} },
4180     { "wallet",             "dumpprivkey",                      &dumpprivkey,                   {"address"}  },
4181     { "wallet",             "dumpwallet",                       &dumpwallet,                    {"filename"} },
4182     { "wallet",             "encryptwallet",                    &encryptwallet,                 {"passphrase"} },
4183     { "wallet",             "getaddressesbylabel",              &getaddressesbylabel,           {"label"} },
4184     { "wallet",             "getaddressinfo",                   &getaddressinfo,                {"address"} },
4185     { "wallet",             "getbalance",                       &getbalance,                    {"dummy","minconf","include_watchonly"} },
4186     { "wallet",             "getnewaddress",                    &getnewaddress,                 {"label","address_type"} },
4187     { "wallet",             "getrawchangeaddress",              &getrawchangeaddress,           {"address_type"} },
4188     { "wallet",             "getreceivedbyaddress",             &getreceivedbyaddress,          {"address","minconf"} },
4189     { "wallet",             "getreceivedbylabel",               &getreceivedbylabel,            {"label","minconf"} },
4190     { "wallet",             "gettransaction",                   &gettransaction,                {"txid","include_watchonly"} },
4191     { "wallet",             "getunconfirmedbalance",            &getunconfirmedbalance,         {} },
4192     { "wallet",             "getwalletinfo",                    &getwalletinfo,                 {} },
4193     { "wallet",             "importaddress",                    &importaddress,                 {"address","label","rescan","p2sh"} },
4194     { "wallet",             "importmulti",                      &importmulti,                   {"requests","options"} },
4195     { "wallet",             "importprivkey",                    &importprivkey,                 {"privkey","label","rescan"} },
4196     { "wallet",             "importprunedfunds",                &importprunedfunds,             {"rawtransaction","txoutproof"} },
4197     { "wallet",             "importpubkey",                     &importpubkey,                  {"pubkey","label","rescan"} },
4198     { "wallet",             "importwallet",                     &importwallet,                  {"filename"} },
4199     { "wallet",             "keypoolrefill",                    &keypoolrefill,                 {"newsize"} },
4200     { "wallet",             "listaddressgroupings",             &listaddressgroupings,          {} },
4201     { "wallet",             "listlabels",                       &listlabels,                    {"purpose"} },
4202     { "wallet",             "listlockunspent",                  &listlockunspent,               {} },
4203     { "wallet",             "listreceivedbyaddress",            &listreceivedbyaddress,         {"minconf","include_empty","include_watchonly","address_filter"} },
4204     { "wallet",             "listreceivedbylabel",              &listreceivedbylabel,           {"minconf","include_empty","include_watchonly"} },
4205     { "wallet",             "listsinceblock",                   &listsinceblock,                {"blockhash","target_confirmations","include_watchonly","include_removed"} },
4206     { "wallet",             "listtransactions",                 &listtransactions,              {"label|dummy","count","skip","include_watchonly"} },
4207     { "wallet",             "listunspent",                      &listunspent,                   {"minconf","maxconf","addresses","include_unsafe","query_options"} },
4208     { "wallet",             "listwalletdir",                    &listwalletdir,                 {} },
4209     { "wallet",             "listwallets",                      &listwallets,                   {} },
4210     { "wallet",             "loadwallet",                       &loadwallet,                    {"filename"} },
4211     { "wallet",             "lockunspent",                      &lockunspent,                   {"unlock","transactions"} },
4212     { "wallet",             "removeprunedfunds",                &removeprunedfunds,             {"txid"} },
4213     { "wallet",             "rescanblockchain",                 &rescanblockchain,              {"start_height", "stop_height"} },
4214     { "wallet",             "sendmany",                         &sendmany,                      {"dummy","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} },
4215     { "wallet",             "sendtoaddress",                    &sendtoaddress,                 {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} },
4216     { "wallet",             "sethdseed",                        &sethdseed,                     {"newkeypool","seed"} },
4217     { "wallet",             "setlabel",                         &setlabel,                      {"address","label"} },
4218     { "wallet",             "settxfee",                         &settxfee,                      {"amount"} },
4219     { "wallet",             "signmessage",                      &signmessage,                   {"address","message"} },
4220     { "wallet",             "signrawtransactionwithwallet",     &signrawtransactionwithwallet,  {"hexstring","prevtxs","sighashtype"} },
4221     { "wallet",             "unloadwallet",                     &unloadwallet,                  {"wallet_name"} },
4222     { "wallet",             "walletcreatefundedpsbt",           &walletcreatefundedpsbt,        {"inputs","outputs","locktime","options","bip32derivs"} },
4223     { "wallet",             "walletlock",                       &walletlock,                    {} },
4224     { "wallet",             "walletpassphrase",                 &walletpassphrase,              {"passphrase","timeout"} },
4225     { "wallet",             "walletpassphrasechange",           &walletpassphrasechange,        {"oldpassphrase","newpassphrase"} },
4226     { "wallet",             "walletprocesspsbt",                &walletprocesspsbt,             {"psbt","sign","sighashtype","bip32derivs"} },
4227 };
4228 // clang-format on
4229 
RegisterWalletRPCCommands(CRPCTable & t)4230 void RegisterWalletRPCCommands(CRPCTable &t)
4231 {
4232     for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
4233         t.appendCommand(commands[vcidx].name, &commands[vcidx]);
4234 }
4235