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