Bitcoin Core 32.99.0
P2P Digital Currency
wallet.cpp
Go to the documentation of this file.
1// Copyright (c) 2010 Satoshi Nakamoto
2// Copyright (c) 2009-present 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 <bitcoin-build-config.h> // IWYU pragma: keep
7
8#include <wallet/rpc/wallet.h>
9
10#include <coins.h>
11#include <core_io.h>
12#include <key.h>
13#include <key_io.h>
14#include <rpc/server.h>
15#include <rpc/util.h>
16#include <univalue.h>
17#include <util/bip32.h>
18#include <util/translation.h>
19#include <wallet/context.h>
20#include <wallet/export.h>
21#include <wallet/receive.h>
22#include <wallet/rpc/util.h>
23#include <wallet/scan.h>
24#include <wallet/wallet.h>
25#include <wallet/walletutil.h>
26
27#include <algorithm>
28#include <optional>
29#include <string_view>
30
31
32namespace wallet {
33
36
37static const std::map<uint64_t, std::string> WALLET_FLAG_CAVEATS{
39 "You need to rescan the blockchain in order to correctly mark used "
40 "destinations in the past. Until this is done, some destinations may "
41 "be considered unused, even if the opposite is the case."},
42};
43
45{
46 return RPCMethod{"getwalletinfo",
47 "Returns an object containing various wallet state info.\n",
48 {},
51 {
52 {
53 {RPCResult::Type::STR, "walletname", "the wallet name"},
54 {RPCResult::Type::NUM, "walletversion", "(DEPRECATED) only related to unsupported legacy wallet, returns the latest version 169900 for backwards compatibility"},
55 {RPCResult::Type::STR, "format", "the database format (only sqlite)"},
56 {RPCResult::Type::NUM, "txcount", "the total number of transactions in the wallet"},
57 {RPCResult::Type::NUM, "keypoolsize", "how many new keys are pre-generated (only counts external keys)"},
58 {RPCResult::Type::NUM, "keypoolsize_hd_internal", "how many new keys are pre-generated for internal use (used for change outputs; 0 if external keys are used for change)"},
59 {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)"},
60 {RPCResult::Type::BOOL, "private_keys_enabled", "false if privatekeys are disabled for this wallet (enforced watch-only wallet)"},
61 {RPCResult::Type::BOOL, "avoid_reuse", "whether this wallet tracks clean/dirty coins in terms of reuse"},
62 {RPCResult::Type::OBJ, "scanning", "current scanning details, or false if no scan is in progress",
63 {
64 {RPCResult::Type::NUM, "duration", "elapsed seconds since scan start"},
65 {RPCResult::Type::NUM, "progress", "scanning progress percentage [0.0, 1.0]"},
66 }, {.skip_type_check=true}, },
67 {RPCResult::Type::BOOL, "descriptors", "whether this wallet uses descriptors for output script management"},
68 {RPCResult::Type::BOOL, "external_signer", "whether this wallet is configured to use an external signer such as a hardware wallet"},
69 {RPCResult::Type::BOOL, "blank", "Whether this wallet intentionally does not contain any keys, scripts, or descriptors"},
70 {RPCResult::Type::NUM_TIME, "birthtime", /*optional=*/true, "The start time for blocks scanning. It could be modified by (re)importing any descriptor with an earlier timestamp."},
71 {RPCResult::Type::ARR, "flags", "The flags currently set on the wallet",
72 {
73 {RPCResult::Type::STR, "flag", "The name of the flag"},
74 }},
76 }},
77 },
79 HelpExampleCli("getwalletinfo", "")
80 + HelpExampleRpc("getwalletinfo", "")
81 },
82 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
83{
84 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
85 if (!pwallet) return UniValue::VNULL;
86
87 // Make sure the results are valid at least up to the most recent block
88 // the user could have gotten from another RPC command prior to now
89 pwallet->BlockUntilSyncedToCurrentChain();
90
91 LOCK(pwallet->cs_wallet);
92
94
95 const int latest_legacy_wallet_minversion{169900};
96
97 size_t kpExternalSize = pwallet->KeypoolCountExternalKeys();
98 obj.pushKV("walletname", pwallet->GetName());
99 obj.pushKV("walletversion", latest_legacy_wallet_minversion);
100 obj.pushKV("format", pwallet->GetDatabase().Format());
101 obj.pushKV("txcount", pwallet->mapWallet.size());
102 obj.pushKV("keypoolsize", kpExternalSize);
103 obj.pushKV("keypoolsize_hd_internal", pwallet->GetKeyPoolSize() - kpExternalSize);
104
105 if (pwallet->HasEncryptionKeys()) {
106 obj.pushKV("unlocked_until", pwallet->nRelockTime);
107 }
108 obj.pushKV("private_keys_enabled", !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
109 obj.pushKV("avoid_reuse", pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE));
110 if (pwallet->Scanner().IsScanning()) {
111 UniValue scanning(UniValue::VOBJ);
112 scanning.pushKV("duration", Ticks<std::chrono::seconds>(pwallet->Scanner().ScanningDuration()));
113 scanning.pushKV("progress", pwallet->Scanner().ScanningProgress());
114 obj.pushKV("scanning", std::move(scanning));
115 } else {
116 obj.pushKV("scanning", false);
117 }
118 obj.pushKV("descriptors", pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
119 obj.pushKV("external_signer", pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER));
120 obj.pushKV("blank", pwallet->IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET));
121 if (int64_t birthtime = pwallet->GetBirthTime(); birthtime != UNKNOWN_TIME) {
122 obj.pushKV("birthtime", birthtime);
123 }
124
125 // Push known flags
127 uint64_t wallet_flags = pwallet->GetWalletFlags();
128 for (uint64_t i = 0; i < 64; ++i) {
129 uint64_t flag = uint64_t{1} << i;
130 if (flag & wallet_flags) {
131 if (flag & KNOWN_WALLET_FLAGS) {
132 flags.push_back(WALLET_FLAG_TO_STRING.at(WalletFlags{flag}));
133 } else {
134 flags.push_back(strprintf("unknown_flag_%u", i));
135 }
136 }
137 }
138 obj.pushKV("flags", flags);
139
140 AppendLastProcessedBlock(obj, *pwallet);
141 return obj;
142},
143 };
144}
145
147{
148 return RPCMethod{"listwalletdir",
149 "Returns a list of wallets in the wallet directory.\n",
150 {},
151 RPCResult{
152 RPCResult::Type::OBJ, "", "",
153 {
154 {RPCResult::Type::ARR, "wallets", "",
155 {
156 {RPCResult::Type::OBJ, "", "",
157 {
158 {RPCResult::Type::STR, "name", "The wallet name"},
159 {RPCResult::Type::ARR, "warnings", "Warning messages related to loading the wallet (may be empty).",
160 {
161 {RPCResult::Type::STR, "", ""},
162 }},
163 }},
164 }},
165 }
166 },
168 HelpExampleCli("listwalletdir", "")
169 + HelpExampleRpc("listwalletdir", "")
170 },
171 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
172{
173 UniValue wallets(UniValue::VARR);
174 for (const auto& [path, db_type] : ListDatabases(GetWalletDir())) {
176 wallet.pushKV("name", path.utf8string());
177 UniValue warnings(UniValue::VARR);
178 if (db_type == "bdb") {
179 warnings.push_back("This wallet is a legacy wallet and will need to be migrated with migratewallet before it can be loaded");
180 }
181 wallet.pushKV("warnings", warnings);
182 wallets.push_back(std::move(wallet));
183 }
184
185 UniValue result(UniValue::VOBJ);
186 result.pushKV("wallets", std::move(wallets));
187 return result;
188},
189 };
190}
191
193{
194 return RPCMethod{"listwallets",
195 "Returns a list of currently loaded wallets.\n"
196 "For full information on the wallet, use \"getwalletinfo\"\n",
197 {},
198 RPCResult{
199 RPCResult::Type::ARR, "", "",
200 {
201 {RPCResult::Type::STR, "walletname", "the wallet name"},
202 }
203 },
205 HelpExampleCli("listwallets", "")
206 + HelpExampleRpc("listwallets", "")
207 },
208 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
209{
211
212 WalletContext& context = EnsureWalletContext(request.context);
213 for (const std::shared_ptr<CWallet>& wallet : GetWallets(context)) {
214 LOCK(wallet->cs_wallet);
215 obj.push_back(wallet->GetName());
216 }
217
218 return obj;
219},
220 };
221}
222
224{
225 return RPCMethod{
226 "loadwallet",
227 "Loads a wallet from a wallet file or directory."
228 "\nNote that all wallet command-line options used when starting bitcoind will be"
229 "\napplied to the new wallet.\n",
230 {
231 {"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The path to the directory of the wallet to be loaded, either absolute or relative to the \"wallets\" directory. The \"wallets\" directory is set by the -walletdir option and defaults to the \"wallets\" folder within the data directory."},
232 {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
233 },
234 RPCResult{
235 RPCResult::Type::OBJ, "", "",
236 {
237 {RPCResult::Type::STR, "name", "The wallet name if loaded successfully."},
238 {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to loading the wallet.",
239 {
240 {RPCResult::Type::STR, "", ""},
241 }},
242 }
243 },
245 "\nLoad wallet from the wallet dir:\n"
246 + HelpExampleCli("loadwallet", "\"walletname\"")
247 + HelpExampleRpc("loadwallet", "\"walletname\"")
248 + "\nLoad wallet using absolute path (Unix):\n"
249 + HelpExampleCli("loadwallet", "\"/path/to/walletname/\"")
250 + HelpExampleRpc("loadwallet", "\"/path/to/walletname/\"")
251 + "\nLoad wallet using absolute path (Windows):\n"
252 + HelpExampleCli("loadwallet", "\"DriveLetter:\\path\\to\\walletname\\\"")
253 + HelpExampleRpc("loadwallet", R"("DriveLetter:\\path\\to\\walletname")")
254 },
255 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
256{
257 WalletContext& context = EnsureWalletContext(request.context);
258 const std::string name(request.params[0].get_str());
259
260 DatabaseOptions options;
261 DatabaseStatus status;
262 ReadDatabaseArgs(*context.args, options);
263 options.require_existing = true;
264 bilingual_str error;
265 std::vector<bilingual_str> warnings;
266 std::optional<bool> load_on_start = request.params[1].isNull() ? std::nullopt : std::optional<bool>(request.params[1].get_bool());
267
268 {
269 LOCK(context.wallets_mutex);
270 if (std::any_of(context.wallets.begin(), context.wallets.end(), [&name](const auto& wallet) { return wallet->GetName() == name; })) {
271 throw JSONRPCError(RPC_WALLET_ALREADY_LOADED, "Wallet \"" + name + "\" is already loaded.");
272 }
273 }
274
275 std::shared_ptr<CWallet> const wallet = LoadWallet(context, name, load_on_start, options, status, error, warnings);
276
277 HandleWalletError(wallet, status, error);
278
280 obj.pushKV("name", wallet->GetName());
281 PushWarnings(warnings, obj);
282
283 return obj;
284},
285 };
286}
287
289{
290 std::string flags;
291 for (auto& it : STRING_TO_WALLET_FLAG)
292 if (it.second & MUTABLE_WALLET_FLAGS)
293 flags += (flags == "" ? "" : ", ") + it.first;
294
295 return RPCMethod{
296 "setwalletflag",
297 "Change the state of the given wallet flag for a wallet.\n",
298 {
299 {"flag", RPCArg::Type::STR, RPCArg::Optional::NO, "The name of the flag to change. Current available flags: " + flags},
300 {"value", RPCArg::Type::BOOL, RPCArg::Default{true}, "The new state."},
301 },
302 RPCResult{
303 RPCResult::Type::OBJ, "", "",
304 {
305 {RPCResult::Type::STR, "flag_name", "The name of the flag that was modified"},
306 {RPCResult::Type::BOOL, "flag_state", "The new state of the flag"},
307 {RPCResult::Type::STR, "warnings", /*optional=*/true, "Any warnings associated with the change"},
308 }
309 },
311 HelpExampleCli("setwalletflag", "avoid_reuse")
312 + HelpExampleRpc("setwalletflag", "\"avoid_reuse\"")
313 },
314 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
315{
316 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
317 if (!pwallet) return UniValue::VNULL;
318
319 std::string flag_str = request.params[0].get_str();
320 bool value = request.params[1].isNull() || request.params[1].get_bool();
321
322 if (!STRING_TO_WALLET_FLAG.contains(flag_str)) {
323 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Unknown wallet flag: %s", flag_str));
324 }
325
326 auto flag = STRING_TO_WALLET_FLAG.at(flag_str);
327
328 if (!(flag & MUTABLE_WALLET_FLAGS)) {
329 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is immutable: %s", flag_str));
330 }
331
333
334 if (pwallet->IsWalletFlagSet(flag) == value) {
335 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is already set to %s: %s", value ? "true" : "false", flag_str));
336 }
337
338 res.pushKV("flag_name", flag_str);
339 res.pushKV("flag_state", value);
340
341 if (value) {
342 pwallet->SetWalletFlag(flag);
343 } else {
344 pwallet->UnsetWalletFlag(flag);
345 }
346
347 if (flag && value && WALLET_FLAG_CAVEATS.contains(flag)) {
348 res.pushKV("warnings", WALLET_FLAG_CAVEATS.at(flag));
349 }
350
351 return res;
352},
353 };
354}
355
357{
358 return RPCMethod{
359 "createwallet",
360 "Creates and loads a new wallet.\n",
361 {
362 {"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."},
363 {"disable_private_keys", RPCArg::Type::BOOL, RPCArg::Default{false}, "Disable the possibility of private keys (only watchonlys are possible in this mode)."},
364 {"blank", RPCArg::Type::BOOL, RPCArg::Default{false}, "Create a blank wallet. A blank wallet has no keys."},
365 {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."},
366 {"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{false}, "Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."},
367 {"descriptors", RPCArg::Type::BOOL, RPCArg::Default{true}, "If set, must be \"true\""},
368 {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
369 {"external_signer", RPCArg::Type::BOOL, RPCArg::Default{false}, "Use an external signer such as a hardware wallet. Requires -signer to be configured. Wallet creation will fail if keys cannot be fetched. Requires disable_private_keys and descriptors set to true."},
370 },
371 RPCResult{
372 RPCResult::Type::OBJ, "", "",
373 {
374 {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."},
375 {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to creating and loading the wallet.",
376 {
377 {RPCResult::Type::STR, "", ""},
378 }},
379 }
380 },
382 HelpExampleCli("createwallet", "\"testwallet\"")
383 + HelpExampleRpc("createwallet", "\"testwallet\"")
384 + HelpExampleCliNamed("createwallet", {{"wallet_name", "descriptors"}, {"avoid_reuse", true}, {"load_on_startup", true}})
385 + HelpExampleRpcNamed("createwallet", {{"wallet_name", "descriptors"}, {"avoid_reuse", true}, {"load_on_startup", true}})
386 },
387 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
388{
389 WalletContext& context = EnsureWalletContext(request.context);
390 uint64_t flags = 0;
391 if (!request.params[1].isNull() && request.params[1].get_bool()) {
393 }
394
395 if (!request.params[2].isNull() && request.params[2].get_bool()) {
397 }
398 SecureString passphrase;
399 passphrase.reserve(100);
400 std::vector<bilingual_str> warnings;
401 if (!request.params[3].isNull()) {
402 passphrase = std::string_view{request.params[3].get_str()};
403 if (passphrase.empty()) {
404 // Empty string means unencrypted
405 warnings.emplace_back(Untranslated("Empty string given as passphrase, wallet will not be encrypted."));
406 }
407 }
408
409 if (!request.params[4].isNull() && request.params[4].get_bool()) {
411 }
413 if (!self.Arg<bool>("descriptors")) {
414 throw JSONRPCError(RPC_WALLET_ERROR, "descriptors argument must be set to \"true\"; it is no longer possible to create a legacy wallet.");
415 }
416 if (!request.params[7].isNull() && request.params[7].get_bool()) {
417#ifdef ENABLE_EXTERNAL_SIGNER
419#else
420 throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without external signing support (required for external signing)");
421#endif
422 }
423
424 DatabaseOptions options;
425 DatabaseStatus status;
426 ReadDatabaseArgs(*context.args, options);
427 options.require_create = true;
428 options.create_flags = flags;
429 options.create_passphrase = passphrase;
430 bilingual_str error;
431 std::optional<bool> load_on_start = request.params[6].isNull() ? std::nullopt : std::optional<bool>(request.params[6].get_bool());
432 const std::shared_ptr<CWallet> wallet = CreateWallet(context, request.params[0].get_str(), load_on_start, options, status, error, warnings);
433 HandleWalletError(wallet, status, error);
434
436 obj.pushKV("name", wallet->GetName());
437 PushWarnings(warnings, obj);
438
439 return obj;
440},
441 };
442}
443
445{
446 return RPCMethod{"unloadwallet",
447 "Unloads the wallet referenced by the request endpoint or the wallet_name argument.\n"
448 "If both are specified, they must be identical.",
449 {
450 {"wallet_name", RPCArg::Type::STR, RPCArg::DefaultHint{"the wallet name from the RPC endpoint"}, "The name of the wallet to unload. If provided both here and in the RPC endpoint, the two must be identical."},
451 {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
452 },
454 {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to unloading the wallet.",
455 {
456 {RPCResult::Type::STR, "", ""},
457 }},
458 }},
460 HelpExampleCli("unloadwallet", "wallet_name")
461 + HelpExampleRpc("unloadwallet", R"("wallet_name")")
462 },
463 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
464{
465 const std::string wallet_name{EnsureUniqueWalletName(request, self.MaybeArg<std::string_view>("wallet_name"))};
466
467 WalletContext& context = EnsureWalletContext(request.context);
468 std::shared_ptr<CWallet> wallet = GetWallet(context, wallet_name);
469 if (!wallet) {
470 throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
471 }
472
473 std::vector<bilingual_str> warnings;
474 {
475 WalletRescanReserver reserver(*wallet);
476 if (!reserver.reserve()) {
477 throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
478 }
479
480 // Release the "main" shared pointer and prevent further notifications.
481 // Note that any attempt to load the same wallet would fail until the wallet
482 // is destroyed (see CheckUniqueFileid).
483 std::optional<bool> load_on_start{self.MaybeArg<bool>("load_on_startup")};
484 if (!RemoveWallet(context, wallet, load_on_start, warnings)) {
485 throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded");
486 }
487 }
488
489 WaitForDeleteWallet(std::move(wallet));
490
491 UniValue result(UniValue::VOBJ);
492 PushWarnings(warnings, result);
493
494 return result;
495},
496 };
497}
498
500{
501 return RPCMethod{
502 "simulaterawtransaction",
503 "Calculate the balance change resulting in the signing and broadcasting of the given transaction(s).\n",
504 {
505 {"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of hex strings of raw transactions.\n",
506 {
508 },
509 },
511 {
512 {"include_watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
513 },
514 },
515 },
516 RPCResult{
517 RPCResult::Type::OBJ, "", "",
518 {
519 {RPCResult::Type::STR_AMOUNT, "balance_change", "The wallet balance change (negative means decrease)."},
520 }
521 },
523 HelpExampleCli("simulaterawtransaction", "[\"myhex\"]")
524 + HelpExampleRpc("simulaterawtransaction", "[\"myhex\"]")
525 },
526 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
527{
528 const std::shared_ptr<const CWallet> rpc_wallet = GetWalletForJSONRPCRequest(request);
529 if (!rpc_wallet) return UniValue::VNULL;
530 const CWallet& wallet = *rpc_wallet;
531
532 LOCK(wallet.cs_wallet);
533
534 const auto& txs = request.params[0].get_array();
535 CAmount changes{0};
536 std::map<COutPoint, CAmount> new_utxos; // UTXO:s that were made available in transaction array
537 std::set<COutPoint> spent;
538
539 for (size_t i = 0; i < txs.size(); ++i) {
541 if (!DecodeHexTx(mtx, txs[i].get_str(), /*try_no_witness=*/ true, /*try_witness=*/ true)) {
542 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Transaction hex string decoding failure.");
543 }
544
545 // Fetch previous transactions (inputs)
546 std::map<COutPoint, Coin> coins;
547 for (const CTxIn& txin : mtx.vin) {
548 coins[txin.prevout]; // Create empty map entry keyed by prevout.
549 }
550 wallet.chain().findCoins(coins);
551
552 // Fetch debit; we are *spending* these; if the transaction is signed and
553 // broadcast, we will lose everything in these
554 for (const auto& txin : mtx.vin) {
555 const auto& outpoint = txin.prevout;
556 if (spent.contains(outpoint)) {
557 throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction(s) are spending the same output more than once");
558 }
559 if (new_utxos.contains(outpoint)) {
560 changes -= new_utxos.at(outpoint);
561 new_utxos.erase(outpoint);
562 } else {
563 if (coins.at(outpoint).IsSpent()) {
564 throw JSONRPCError(RPC_INVALID_PARAMETER, "One or more transaction inputs are missing or have been spent already");
565 }
566 changes -= wallet.GetDebit(txin);
567 }
568 spent.insert(outpoint);
569 }
570
571 // Iterate over outputs; we are *receiving* these, if the wallet considers
572 // them "mine"; if the transaction is signed and broadcast, we will receive
573 // everything in these
574 // Also populate new_utxos in case these are spent in later transactions
575
576 const auto& hash = mtx.GetHash();
577 for (size_t i = 0; i < mtx.vout.size(); ++i) {
578 const auto& txout = mtx.vout[i];
579 bool is_mine = wallet.IsMine(txout);
580 changes += new_utxos[COutPoint(hash, i)] = is_mine ? txout.nValue : 0;
581 }
582 }
583
584 UniValue result(UniValue::VOBJ);
585 result.pushKV("balance_change", ValueFromAmount(changes));
586
587 return result;
588}
589 };
590}
591
593{
594 return RPCMethod{
595 "migratewallet",
596 "Migrate the wallet to a descriptor wallet.\n"
597 "A new wallet backup will need to be made.\n"
598 "\nThe migration process will create a backup of the wallet before migrating. This backup\n"
599 "file will be named <wallet name>-<timestamp>.legacy.bak and can be found in the directory\n"
600 "for this wallet. In the event of an incorrect migration, the backup can be restored using restorewallet."
601 "\nEncrypted wallets must have the passphrase provided as an argument to this call.\n"
602 "\nThis RPC may take a long time to complete. Increasing the RPC client timeout is recommended.",
603 {
604 {"wallet_name", RPCArg::Type::STR, RPCArg::DefaultHint{"the wallet name from the RPC endpoint"}, "The name of the wallet to migrate. If provided both here and in the RPC endpoint, the two must be identical."},
605 {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "The wallet passphrase"},
606 {"load_wallet", RPCArg::Type::BOOL, RPCArg::Default{true}, "Load the wallet after migration."},
607 },
608 RPCResult{
609 RPCResult::Type::OBJ, "", "",
610 {
611 {RPCResult::Type::STR, "wallet_name", "The name of the primary migrated wallet"},
612 {RPCResult::Type::STR, "watchonly_name", /*optional=*/true, "The name of the migrated wallet containing the watchonly scripts"},
613 {RPCResult::Type::STR, "solvables_name", /*optional=*/true, "The name of the migrated wallet containing solvable but not watched scripts"},
614 {RPCResult::Type::STR, "backup_path", "The location of the backup of the original wallet"},
615 }
616 },
618 HelpExampleCli("migratewallet", "")
619 + HelpExampleRpc("migratewallet", "")
620 },
621 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
622 {
623 const std::string wallet_name{EnsureUniqueWalletName(request, self.MaybeArg<std::string_view>("wallet_name"))};
624
625 SecureString wallet_pass;
626 wallet_pass.reserve(100);
627 if (!request.params[1].isNull()) {
628 wallet_pass = std::string_view{request.params[1].get_str()};
629 }
630
631 const bool loadwallet = self.Arg<bool>("load_wallet");
632
633 WalletContext& context = EnsureWalletContext(request.context);
634 util::Result<MigrationResult> res = MigrateLegacyToDescriptor(wallet_name, wallet_pass, context, loadwallet);
635 if (!res) {
636 throw JSONRPCError(RPC_WALLET_ERROR, util::ErrorString(res).original);
637 }
638
640 r.pushKV("wallet_name", res->wallet_name);
641 if (res->watchonly_wallet_name.has_value()) {
642 r.pushKV("watchonly_name", res->watchonly_wallet_name.value());
643 }
644 if (res->solvables_wallet_name.has_value()) {
645 r.pushKV("solvables_name", res->solvables_wallet_name.value());
646 }
647 r.pushKV("backup_path", res->backup_path.utf8string());
648
649 return r;
650 },
651 };
652}
653
655{
656 return RPCMethod{
657 "gethdkeys",
658 "List all BIP 32 HD keys in the wallet and which descriptors use them.\n",
659 {
661 {"active_only", RPCArg::Type::BOOL, RPCArg::Default{false}, "Show the keys for only active descriptors"},
662 {"private", RPCArg::Type::BOOL, RPCArg::Default{false}, "Show private keys"}
663 }},
664 },
666 {
667 {RPCResult::Type::OBJ, "", "", {
668 {RPCResult::Type::STR, "xpub", "The extended public key"},
669 {RPCResult::Type::BOOL, "has_private", "Whether the wallet has the private key for this xpub"},
670 {RPCResult::Type::STR, "xprv", /*optional=*/true, "The extended private key if \"private\" is true"},
671 {RPCResult::Type::ARR, "descriptors", "Array of descriptor objects that use this HD key",
672 {
673 {RPCResult::Type::OBJ, "", "", {
674 {RPCResult::Type::STR, "desc", "Descriptor string public representation"},
675 {RPCResult::Type::BOOL, "active", "Whether this descriptor is currently used to generate new addresses"},
676 }},
677 }},
678 }},
679 }
680 }},
682 HelpExampleCli("gethdkeys", "") + HelpExampleRpc("gethdkeys", "")
683 + HelpExampleCliNamed("gethdkeys", {{"active_only", "true"}, {"private", "true"}}) + HelpExampleRpcNamed("gethdkeys", {{"active_only", "true"}, {"private", "true"}})
684 },
685 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
686 {
687 const std::shared_ptr<const CWallet> wallet = GetWalletForJSONRPCRequest(request);
688 if (!wallet) return UniValue::VNULL;
689
690 LOCK(wallet->cs_wallet);
691
692 UniValue options{request.params[0].isNull() ? UniValue::VOBJ : request.params[0]};
693 const bool active_only{options.exists("active_only") ? options["active_only"].get_bool() : false};
694 const bool priv{options.exists("private") ? options["private"].get_bool() : false};
695 if (priv) {
697 }
698
699 std::map<CExtPubKey, std::set<std::tuple<std::string, bool, bool>>> wallet_xpubs;
700 std::map<CExtPubKey, CExtKey> wallet_xprvs;
701 for (const auto& [xpub, spkms] : wallet->GetHDPubKeys(active_only ? HDKeyFilter::Active : HDKeyFilter::All)) {
702 for (auto* desc_spkm : spkms) {
703 LOCK(desc_spkm->cs_desc_man);
704 std::string desc_str;
705 bool ok = desc_spkm->GetDescriptorString(desc_str, /*priv=*/false);
706 CHECK_NONFATAL(ok);
707 wallet_xpubs[xpub].emplace(desc_str, wallet->IsActiveScriptPubKeyMan(*desc_spkm), desc_spkm->HasPrivKey(xpub.pubkey.GetID()));
708 if (std::optional<CKey> key = priv ? desc_spkm->GetKey(xpub.pubkey.GetID()) : std::nullopt) {
709 wallet_xprvs[xpub] = CExtKey(xpub, *key);
710 }
711 }
712 }
713
714 UniValue response(UniValue::VARR);
715 for (const auto& [xpub, descs] : wallet_xpubs) {
716 bool has_xprv = false;
717 UniValue descriptors(UniValue::VARR);
718 for (const auto& [desc, active, has_priv] : descs) {
720 d.pushKV("desc", desc);
721 d.pushKV("active", active);
722 has_xprv |= has_priv;
723
724 descriptors.push_back(std::move(d));
725 }
726 UniValue xpub_info(UniValue::VOBJ);
727 xpub_info.pushKV("xpub", EncodeExtPubKey(xpub));
728 xpub_info.pushKV("has_private", has_xprv);
729 if (priv && has_xprv) {
730 xpub_info.pushKV("xprv", EncodeExtKey(wallet_xprvs.at(xpub)));
731 }
732 xpub_info.pushKV("descriptors", std::move(descriptors));
733
734 response.push_back(std::move(xpub_info));
735 }
736
737 return response;
738 },
739 };
740}
741
743{
744 return RPCMethod{"createwalletdescriptor",
745 "Creates the wallet's descriptor for the given address type. "
746 "The address type must be one that the wallet does not already have a descriptor for."
748 {
749 {"type", RPCArg::Type::STR, RPCArg::Optional::NO, "The address type the descriptor will produce. Options are " + FormatAllOutputTypes() + "."},
751 {"internal", RPCArg::Type::BOOL, RPCArg::DefaultHint{"Both external and internal will be generated unless this parameter is specified"}, "Whether to only make one descriptor that is internal (if parameter is true) or external (if parameter is false)"},
752 {"hdkey", RPCArg::Type::STR, RPCArg::DefaultHint{"The HD key used by all other active descriptors"}, "The HD key that the wallet knows the private key of, listed using 'gethdkeys', to use for this descriptor's key"},
753 }},
754 },
755 RPCResult{
756 RPCResult::Type::OBJ, "", "",
757 {
758 {RPCResult::Type::ARR, "descs", "The public descriptors that were added to the wallet",
759 {{RPCResult::Type::STR, "", ""}}
760 }
761 },
762 },
764 HelpExampleCli("createwalletdescriptor", "bech32m")
765 + HelpExampleRpc("createwalletdescriptor", R"("bech32m")")
766 },
767 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
768 {
769 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
770 if (!pwallet) return UniValue::VNULL;
771
772 std::optional<OutputType> output_type = ParseOutputType(request.params[0].get_str());
773 if (!output_type) {
774 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[0].get_str()));
775 }
776
777 UniValue options{request.params[1].isNull() ? UniValue::VOBJ : request.params[1]};
778 UniValue internal_only{options["internal"]};
779 UniValue hdkey{options["hdkey"]};
780
781 std::vector<bool> internals;
782 if (internal_only.isNull()) {
783 internals.push_back(false);
784 internals.push_back(true);
785 } else {
786 internals.push_back(internal_only.get_bool());
787 }
788
789 LOCK(pwallet->cs_wallet);
790 EnsureWalletIsUnlocked(*pwallet);
791
792 CExtPubKey xpub;
793 if (hdkey.isNull()) {
794 HDPubKeyMap active_xpubs = pwallet->GetHDPubKeys(HDKeyFilter::Active);
795 if (active_xpubs.size() != 1) {
796 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to determine which HD key to use from active descriptors. Please specify with 'hdkey'");
797 }
798 xpub = active_xpubs.begin()->first;
799 } else {
800 xpub = DecodeExtPubKey(hdkey.get_str());
801 if (!xpub.pubkey.IsValid()) {
802 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to parse HD key. Please provide a valid xpub");
803 }
804 }
805
806 std::optional<CKey> key = pwallet->GetKey(xpub.pubkey.GetID());
807 if (!key) {
808 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Private key for %s is not known", EncodeExtPubKey(xpub)));
809 }
810 CExtKey active_hdkey(xpub, *key);
811
812 std::vector<std::reference_wrapper<DescriptorScriptPubKeyMan>> spkms;
813 WalletBatch batch{pwallet->GetDatabase()};
814 for (bool internal : internals) {
815 WalletDescriptor w_desc = GenerateWalletDescriptor(xpub, *output_type, internal);
816 if (!pwallet->GetDescriptorScriptPubKeyMan(w_desc)) {
817 spkms.emplace_back(pwallet->SetupDescriptorScriptPubKeyMan(batch, active_hdkey, *output_type, internal));
818 }
819 }
820 if (spkms.empty()) {
821 throw JSONRPCError(RPC_WALLET_ERROR, "Descriptor already exists");
822 }
823
824 // Fetch each descspkm from the wallet in order to get the descriptor strings
826 for (const auto& spkm : spkms) {
827 std::string desc_str;
828 bool ok = spkm.get().GetDescriptorString(desc_str, false);
829 CHECK_NONFATAL(ok);
830 descs.push_back(desc_str);
831 }
833 out.pushKV("descs", std::move(descs));
834 return out;
835 }
836 };
837}
838
840{
841 return RPCMethod{
842 "addhdkey",
843 "Add a BIP 32 HD key to the wallet that can be used with 'createwalletdescriptor'\n",
844 {
845 {"hdkey", RPCArg::Type::STR, RPCArg::DefaultHint{"Automatically generated new key"}, "The BIP 32 extended private key to add. If none is provided, a randomly generated one will be added."},
846 },
847 RPCResult{
848 RPCResult::Type::OBJ, "", "",
849 {
850 {RPCResult::Type::STR, "xpub", "The xpub of the HD key that was added to the wallet"}
851 },
852 },
854 HelpExampleCli("addhdkey", "xprv") + HelpExampleRpc("addhdkey", R"("xprv")")
855 },
856 [&](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
857 {
858 std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
859 if (!wallet) return UniValue::VNULL;
860
861 if (wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
862 throw JSONRPCError(RPC_WALLET_ERROR, "addhdkey is not available for wallets without private keys");
863 }
864
866
867 std::optional<CExtKey> hdkey;
868 if (!request.params[0].isNull()) {
869 hdkey = DecodeExtKey(request.params[0].get_str());
870 if (!hdkey->key.IsValid()) {
871 // Check if the user gave us an xpub and give a more descriptive error if so
872 CExtPubKey xpub = DecodeExtPubKey(request.params[0].get_str());
873 if (xpub.pubkey.IsValid()) {
874 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Extended public key (xpub) provided, but extended private key (xprv) is required");
875 } else {
876 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Could not parse HD key");
877 }
878 }
879 }
880
881 auto res = wallet->AddHDKey(hdkey);
882 if (!res) {
883 if (res.error().code == wallet::WalletErrorCode::UnlockNeeded) {
884 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, res.error().message.original);
885 }
886 throw JSONRPCError(RPC_WALLET_ERROR, res.error().message.original);
887 }
888
889 UniValue response(UniValue::VOBJ);
890 response.pushKV("xpub", EncodeExtPubKey(*res));
891 return response;
892 },
893 };
894}
895
897{
898 return RPCMethod{"exportwatchonlywallet",
899 "Creates a wallet file at the specified destination containing a watchonly version "
900 "of the current wallet. This watchonly wallet contains the wallet's public descriptors, "
901 "its transactions, and address book data. Descriptors that use hardened derivation will "
902 "only have a limited number of derived keys included in the export due to hardened "
903 "derivation requiring private keys. Descriptors with unhardened derivation do not have "
904 "this limitation. The watchonly wallet can be imported into another node using 'restorewallet'.",
905 {
906 {"destination", RPCArg::Type::STR, RPCArg::Optional::NO, "The path to the filename the exported watchonly wallet will be saved to"},
907 },
908 RPCResult{
909 RPCResult::Type::OBJ, "", "",
910 {
911 {RPCResult::Type::STR, "exported_file", "The full path that the file has been exported to"},
912 },
913 },
915 HelpExampleCli("exportwatchonlywallet", "\"/path/to/export.dat\"")
916 + HelpExampleRpc("exportwatchonlywallet", "\"/path/to/export.dat\"")
917 },
918 [&](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
919 {
920 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
921 if (!pwallet) return UniValue::VNULL;
922 WalletContext& context = EnsureWalletContext(request.context);
923
924 std::string dest = request.params[0].get_str();
925
926 LOCK(pwallet->cs_wallet);
927 pwallet->TopUpKeyPool();
928 util::Result<std::string> exported = ExportWatchOnlyWallet(*pwallet, fs::PathFromString(dest), context);
929 if (!exported) {
930 throw JSONRPCError(RPC_WALLET_ERROR, util::ErrorString(exported).original);
931 }
933 out.pushKV("exported_file", *exported);
934 return out;
935 }
936 };
937}
938
940{
941 return RPCMethod{
942 "derivehdkey",
943 "Derive extended public or private key from HD key in the wallet at a given path.\n"
944 "Derivation uses wallet private key material.\n"
946 {
947 {"path", RPCArg::Type::STR, RPCArg::Optional::NO, "BIP 32 derivation path with at least one hardened step."},
949 {"private", RPCArg::Type::BOOL, RPCArg::Default{false}, "Show private key"},
950 {"hdkey", RPCArg::Type::STR, RPCArg::DefaultHint{"Either the HD key of an unused(KEY) descriptor, or any other active descriptor."}, "The HD key that the wallet knows the private key of, listed using 'gethdkeys', to use for derivation"},
951 }},
952 },
953 RPCResult{
954 RPCResult::Type::OBJ, "", "", {
955 {RPCResult::Type::STR, "origin", "Fingerprint and path for use in descriptors"},
956 {RPCResult::Type::STR, "xpub", "The extended public key"},
957 {RPCResult::Type::STR, "xprv", /*optional=*/true, "The extended private key if \"private\" is true"},
958 },
959 },
961 HelpExampleCli("derivehdkey", "m/87h/0h/0h") + HelpExampleRpc("derivehdkey", "\"m/87h/0h/0h\"")
962 + HelpExampleCliNamed("derivehdkey", {{"path", "m/87h/0h/0h"}, {"private", "true"}})
963 + HelpExampleRpcNamed("derivehdkey", {{"path", "m/87h/0h/0h"}, {"private", "true"}})
964 },
965 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
966 {
967 const std::shared_ptr<const CWallet> wallet = GetWalletForJSONRPCRequest(request);
968 if (!wallet) return UniValue::VNULL;
969
970 if (wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
971 // Watch-only wallets can't contain unused(KEY) descriptors
972 throw JSONRPCError(RPC_WALLET_ERROR, "derivehdkey is not available for watch-only wallets");
973 }
974
975 std::vector<uint32_t> path = ParsePathBIP32(request.params[0].get_str());
976 UniValue options{request.params[1].isNull() ? UniValue::VOBJ : request.params[1]};
977 const bool priv{options.exists("private") ? options["private"].get_bool() : false};
978 UniValue hdkey{options["hdkey"]};
979 if (!HasHardenedDerivation(path)) {
980 throw JSONRPCError(RPC_INVALID_PARAMETER, "Derivation path requires at least one hardened step");
981 }
982
983 LOCK(wallet->cs_wallet);
984
985 // The RPC requires a hardened derivation step, so always unlock
986 // the wallet.
988
989 CExtPubKey xpub;
990 if (!hdkey.isNull()) {
991 xpub = DecodeExtPubKey(hdkey.get_str());
992 if (!xpub.pubkey.IsValid()) {
993 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to parse HD key. Please provide a valid xpub");
994 }
995
996 // Accept an xpub from an active or unused(KEY) descriptor, but
997 // not from a (used) inactive one.
998 std::set<CExtPubKey> xpub_candidates;
999 for (const auto& candidate : wallet->GetHDPubKeys(HDKeyFilter::UnusedKey)) {
1000 xpub_candidates.insert(candidate.first);
1001 }
1002 for (const auto& candidate : wallet->GetHDPubKeys(HDKeyFilter::Active)) {
1003 xpub_candidates.insert(candidate.first);
1004 }
1005 if (!xpub_candidates.contains(xpub)) {
1006 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "HD key is not used by an active or unused(KEY) descriptor");
1007 }
1008 }
1009
1010 // If hdkey was not specified, try to look it up. First consider
1011 // unused(KEY) descriptors. Otherwise look for active descriptors.
1012 if (hdkey.isNull()) {
1013 HDPubKeyMap wallet_xpubs{wallet->GetHDPubKeys(HDKeyFilter::UnusedKey)};
1014
1015 if (wallet_xpubs.size() > 1) {
1016 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to determine which HD key to use. Please specify with 'hdkey'");
1017 } else if (wallet_xpubs.size() == 1) {
1018 xpub = wallet_xpubs.begin()->first;
1019 } else {
1020 HDPubKeyMap active_xpubs = wallet->GetHDPubKeys(HDKeyFilter::Active);
1021 if (active_xpubs.empty()) {
1022 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No active or unused(KEY) descriptor found");
1023 }
1024
1025 if (active_xpubs.size() > 1) {
1026 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to determine which HD key to use from active descriptors. Please specify with 'hdkey'");
1027 }
1028
1029 xpub = active_xpubs.begin()->first;
1030 }
1031 }
1032
1033 std::optional<CExtKey> xprv{wallet->GetExtKey(xpub)};
1034 if (!xprv) {
1035 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Private key for %s is not known", EncodeExtPubKey(xpub)));
1036 }
1037
1038 std::optional<std::pair<CExtKey, KeyOriginInfo>> child{DeriveExtKey(*xprv, path)};
1039 if (!child) {
1040 throw JSONRPCError(RPC_INVALID_PARAMETER, "Unable to derive HD key at the requested path");
1041 }
1042
1044
1045 const std::string fingerprint{HexStr(child->second.fingerprint)};
1046
1047 res.pushKV("origin", strprintf("[%s%s]", fingerprint, FormatHDKeypath(child->second.path)));
1048 res.pushKV("xpub", EncodeExtPubKey(child->first.Neuter()));
1049 if (priv) {
1050 res.pushKV("xprv", EncodeExtKey(child->first));
1051 }
1052 return res;
1053 },
1054 };
1055}
1056
1057// addresses
1066#ifdef ENABLE_EXTERNAL_SIGNER
1068#endif // ENABLE_EXTERNAL_SIGNER
1069
1070// backup
1077
1078// coins
1086
1087// encryption
1092
1093// spend
1099RPCMethod send();
1104
1105// signmessage
1107
1108// transactions
1117
1118std::span<const CRPCCommand> GetWalletRPCCommands()
1119{
1120 static const CRPCCommand commands[]{
1121 {"rawtransactions", &fundrawtransaction},
1122 {"wallet", &abandontransaction},
1123 {"wallet", &abortrescan},
1124 {"wallet", &addhdkey},
1125 {"wallet", &backupwallet},
1126 {"wallet", &bumpfee},
1127 {"wallet", &psbtbumpfee},
1128 {"wallet", &createwallet},
1129 {"wallet", &createwalletdescriptor},
1130 {"wallet", &derivehdkey},
1131 {"wallet", &restorewallet},
1132 {"wallet", &encryptwallet},
1133 {"wallet", &exportwatchonlywallet},
1134 {"wallet", &getaddressesbylabel},
1135 {"wallet", &getaddressinfo},
1136 {"wallet", &getbalance},
1137 {"wallet", &gethdkeys},
1138 {"wallet", &getnewaddress},
1139 {"wallet", &getrawchangeaddress},
1140 {"wallet", &getreceivedbyaddress},
1141 {"wallet", &getreceivedbylabel},
1142 {"wallet", &gettransaction},
1143 {"wallet", &getbalances},
1144 {"wallet", &getwalletinfo},
1145 {"wallet", &importdescriptors},
1146 {"wallet", &importprunedfunds},
1147 {"wallet", &keypoolrefill},
1148 {"wallet", &listaddressgroupings},
1149 {"wallet", &listdescriptors},
1150 {"wallet", &listlabels},
1151 {"wallet", &listlockunspent},
1152 {"wallet", &listreceivedbyaddress},
1153 {"wallet", &listreceivedbylabel},
1154 {"wallet", &listsinceblock},
1155 {"wallet", &listtransactions},
1156 {"wallet", &listunspent},
1157 {"wallet", &listwalletdir},
1158 {"wallet", &listwallets},
1159 {"wallet", &loadwallet},
1160 {"wallet", &lockunspent},
1161 {"wallet", &migratewallet},
1162 {"wallet", &removeprunedfunds},
1163 {"wallet", &rescanblockchain},
1164 {"wallet", &send},
1165 {"wallet", &sendmany},
1166 {"wallet", &sendtoaddress},
1167 {"wallet", &setlabel},
1168 {"wallet", &setwalletflag},
1169 {"wallet", &signmessage},
1170 {"wallet", &signrawtransactionwithwallet},
1171 {"wallet", &simulaterawtransaction},
1172 {"wallet", &sendall},
1173 {"wallet", &unloadwallet},
1174 {"wallet", &walletcreatefundedpsbt},
1175#ifdef ENABLE_EXTERNAL_SIGNER
1176 {"wallet", &walletdisplayaddress},
1177#endif // ENABLE_EXTERNAL_SIGNER
1178 {"wallet", &walletlock},
1179 {"wallet", &walletpassphrase},
1180 {"wallet", &walletpassphrasechange},
1181 {"wallet", &walletprocesspsbt},
1182 };
1183 return commands;
1184}
1185} // namespace wallet
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
std::string FormatHDKeypath(const std::vector< uint32_t > &path, bool apostrophe)
Definition: bip32.cpp:62
bool HasHardenedDerivation(std::span< const uint32_t > keypath)
Whether a parsed HD keypath contains at least one hardened derivation step.
Definition: bip32.cpp:77
int flags
Definition: bitcoin-tx.cpp:530
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:112
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:30
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:166
bool IsValid() const
Definition: pubkey.h:191
An input of a transaction.
Definition: transaction.h:63
COutPoint prevout
Definition: transaction.h:65
auto MaybeArg(std::string_view key) const
Helper to get an optional request argument.
Definition: util.h:502
auto Arg(std::string_view key) const
Helper to get a required or default-valued request argument.
Definition: util.h:470
void push_back(UniValue val)
Definition: univalue.cpp:103
@ VNULL
Definition: univalue.h:24
@ VOBJ
Definition: univalue.h:24
@ VARR
Definition: univalue.h:24
bool isNull() const
Definition: univalue.h:81
void pushKV(std::string key, UniValue val)
Definition: univalue.cpp:125
bool has_value() const noexcept
std::optional methods, so functions returning optional<T> can change to return Result<T> with minimal...
Definition: result.h:64
const T & value() const LIFETIMEBOUND
Definition: result.h:65
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:313
std::map< CExtPubKey, std::set< DescriptorScriptPubKeyMan * > > HDPubKeyMap
Definition: wallet.h:1065
HDKeyFilter
Which descriptors GetHDPubKeys() should consider.
Definition: wallet.h:1060
Access to the wallet database.
Definition: walletdb.h:197
Descriptor with some wallet metadata.
Definition: walletutil.h:64
RAII object to check and reserve a wallet rescan.
Definition: scan.h:37
bool reserve(bool with_passphrase=false)
Definition: scan.cpp:40
bool DecodeHexTx(CMutableTransaction &tx, const std::string &hex_tx, bool try_no_witness, bool try_witness)
Definition: core_io.cpp:225
UniValue ValueFromAmount(const CAmount amount)
Definition: core_io.cpp:283
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:183
std::string HexStr(const std::span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
Definition: hex_base.cpp:30
std::optional< std::pair< CExtKey, KeyOriginInfo > > DeriveExtKey(const CExtKey &ext_key, const std::vector< uint32_t > &path)
Get extended key and origin info for a given path.
Definition: key.cpp:369
std::string EncodeExtKey(const CExtKey &key)
Definition: key_io.cpp:284
CExtPubKey DecodeExtPubKey(const std::string &str)
Definition: key_io.cpp:245
std::string EncodeExtPubKey(const CExtPubKey &key)
Definition: key_io.cpp:258
CExtKey DecodeExtKey(const std::string &str)
Definition: key_io.cpp:268
void ReadDatabaseArgs(const ArgsManager &args, DBOptions &options)
bilingual_str ErrorString(const Result< T > &result)
Definition: result.h:93
RPCMethod abandontransaction()
RPCMethod walletpassphrase()
Definition: encrypt.cpp:14
void ReadDatabaseArgs(const ArgsManager &args, DatabaseOptions &options)
Definition: db.cpp:153
std::shared_ptr< CWallet > LoadWallet(WalletContext &context, const std::string &name, std::optional< bool > load_on_start, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error, std::vector< bilingual_str > &warnings)
Definition: wallet.cpp:321
RPCMethod abortrescan()
RPCMethod gettransaction()
RPCMethod send()
Definition: spend.cpp:1180
std::shared_ptr< CWallet > GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
Definition: util.cpp:62
RPCMethod simulaterawtransaction()
Definition: wallet.cpp:499
RPCMethod fundrawtransaction()
Definition: spend.cpp:709
std::vector< std::shared_ptr< CWallet > > GetWallets(WalletContext &context)
Definition: wallet.cpp:206
CWallet::HDPubKeyMap HDPubKeyMap
Definition: wallet.cpp:34
RPCMethod listsinceblock()
static RPCMethod unloadwallet()
Definition: wallet.cpp:444
const RPCResult RESULT_LAST_PROCESSED_BLOCK
Definition: util.h:29
RPCMethod walletpassphrasechange()
Definition: encrypt.cpp:119
void HandleWalletError(const std::shared_ptr< CWallet > &wallet, DatabaseStatus &status, bilingual_str &error)
Definition: util.cpp:124
RPCMethod importdescriptors()
Definition: backup.cpp:175
util::Result< MigrationResult > MigrateLegacyToDescriptor(std::shared_ptr< CWallet > local_wallet, const SecureString &passphrase, WalletContext &context, bool load_wallet)
Requirement: The wallet provided to this function must be isolated, with no attachment to the node's ...
Definition: wallet.cpp:4190
RPCMethod gethdkeys()
Definition: wallet.cpp:654
RPCMethod listlockunspent()
Definition: coins.cpp:348
RPCMethod getreceivedbyaddress()
Definition: coins.cpp:80
static RPCMethod createwalletdescriptor()
Definition: wallet.cpp:742
void EnsureWalletIsUnlocked(const CWallet &wallet)
Definition: util.cpp:85
std::string EnsureUniqueWalletName(const JSONRPCRequest &request, std::optional< std::string_view > wallet_name)
Ensures that a wallet name is specified across the endpoint and wallet_name.
Definition: util.cpp:33
RPCMethod rescanblockchain()
RPCMethod walletcreatefundedpsbt()
Definition: spend.cpp:1674
const std::string HELP_REQUIRING_PASSPHRASE
Definition: util.cpp:20
static RPCMethod setwalletflag()
Definition: wallet.cpp:288
@ UnlockNeeded
The wallet is locked and the operation requires access to private keys.
RPCMethod listtransactions()
RPCMethod getaddressinfo()
Definition: addresses.cpp:413
bool RemoveWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet, std::optional< bool > load_on_start)
Definition: wallet.cpp:200
WalletContext & EnsureWalletContext(const std::any &context)
Definition: util.cpp:92
RPCMethod removeprunedfunds()
Definition: backup.cpp:97
RPCMethod encryptwallet()
Definition: encrypt.cpp:222
RPCMethod lockunspent()
Definition: coins.cpp:215
fs::path GetWalletDir()
Get the path of the wallet directory.
Definition: walletutil.cpp:13
RPCMethod listreceivedbyaddress()
RPCMethod sendall()
Definition: spend.cpp:1303
RPCMethod walletdisplayaddress()
Definition: addresses.cpp:680
RPCMethod getbalance()
Definition: coins.cpp:164
RPCMethod listaddressgroupings()
Definition: addresses.cpp:157
RPCMethod importprunedfunds()
Definition: backup.cpp:42
RPCMethod derivehdkey()
Definition: wallet.cpp:939
constexpr int64_t UNKNOWN_TIME
Constant representing an unknown spkm creation time.
RPCMethod getbalances()
Definition: coins.cpp:402
RPCMethod keypoolrefill()
Definition: addresses.cpp:218
RPCMethod walletlock()
Definition: encrypt.cpp:179
RPCMethod signrawtransactionwithwallet()
Definition: spend.cpp:843
RPCMethod listdescriptors()
Definition: backup.cpp:313
void AppendLastProcessedBlock(UniValue &entry, const CWallet &wallet)
Definition: util.cpp:178
RPCMethod walletprocesspsbt()
Definition: spend.cpp:1590
util::Result< std::string > ExportWatchOnlyWallet(const CWallet &wallet, const fs::path &destination, WalletContext &context)
Make a new watchonly wallet file containing the public descriptors from this wallet The exported watc...
Definition: export.cpp:47
RPCMethod addhdkey()
Definition: wallet.cpp:839
RPCMethod psbtbumpfee()
Definition: spend.cpp:1178
RPCMethod getaddressesbylabel()
Definition: addresses.cpp:562
static RPCMethod migratewallet()
Definition: wallet.cpp:592
constexpr uint64_t KNOWN_WALLET_FLAGS
Definition: wallet.h:153
RPCMethod bumpfee()
Definition: spend.cpp:1177
static RPCMethod exportwatchonlywallet()
Definition: wallet.cpp:896
static RPCMethod loadwallet()
Definition: wallet.cpp:223
RPCMethod listunspent()
Definition: coins.cpp:457
RPCMethod signmessage()
Definition: signmessage.cpp:14
RPCMethod listlabels()
Definition: addresses.cpp:623
static const std::map< uint64_t, std::string > WALLET_FLAG_CAVEATS
Definition: wallet.cpp:37
static RPCMethod listwallets()
Definition: wallet.cpp:192
RPCMethod getreceivedbylabel()
Definition: coins.cpp:122
static RPCMethod getwalletinfo()
Definition: wallet.cpp:44
std::shared_ptr< CWallet > CreateWallet(WalletContext &context, const std::string &name, std::optional< bool > load_on_start, DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error, std::vector< bilingual_str > &warnings)
Definition: wallet.cpp:334
RPCMethod sendtoaddress()
Definition: spend.cpp:242
RPCMethod backupwallet()
Definition: backup.cpp:396
static RPCMethod listwalletdir()
Definition: wallet.cpp:146
RPCMethod listreceivedbylabel()
RPCMethod getrawchangeaddress()
Definition: addresses.cpp:72
WalletFlags
Definition: walletutil.h:15
@ WALLET_FLAG_EXTERNAL_SIGNER
Indicates that the wallet needs an external signer.
Definition: walletutil.h:56
@ WALLET_FLAG_AVOID_REUSE
Definition: walletutil.h:21
@ WALLET_FLAG_DESCRIPTORS
Indicate that this wallet supports DescriptorScriptPubKeyMan.
Definition: walletutil.h:53
@ WALLET_FLAG_DISABLE_PRIVATE_KEYS
Definition: walletutil.h:30
@ WALLET_FLAG_BLANK_WALLET
Flag set when a wallet contains no HD seed and no private keys, scripts, addresses,...
Definition: walletutil.h:50
void WaitForDeleteWallet(std::shared_ptr< CWallet > &&wallet)
Explicitly delete the wallet.
Definition: wallet.cpp:266
RPCMethod sendmany()
Definition: spend.cpp:341
static const std::map< std::string, WalletFlags > STRING_TO_WALLET_FLAG
Definition: wallet.h:175
constexpr uint64_t MUTABLE_WALLET_FLAGS
Definition: wallet.h:162
std::shared_ptr< CWallet > GetWallet(WalletContext &context, const std::string &name)
Definition: wallet.cpp:219
RPCMethod getnewaddress()
Definition: addresses.cpp:21
static RPCMethod createwallet()
Definition: wallet.cpp:356
std::span< const CRPCCommand > GetWalletRPCCommands()
Definition: wallet.cpp:1118
static const std::map< WalletFlags, std::string > WALLET_FLAG_TO_STRING
Definition: wallet.h:165
RPCMethod restorewallet()
Definition: backup.cpp:431
std::vector< std::pair< fs::path, std::string > > ListDatabases(const fs::path &wallet_dir)
Recursively list database paths in directory.
Definition: db.cpp:23
RPCMethod setlabel()
Definition: addresses.cpp:118
DatabaseStatus
Definition: db.h:180
WalletDescriptor GenerateWalletDescriptor(const CExtPubKey &master_key, const OutputType &addr_type, bool internal)
Definition: walletutil.cpp:35
std::optional< OutputType > ParseOutputType(std::string_view type)
Definition: outputtype.cpp:23
std::string FormatAllOutputTypes()
Definition: outputtype.cpp:49
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:75
const char * name
Definition: rest.cpp:71
@ RPC_WALLET_UNLOCK_NEEDED
Enter the wallet passphrase with walletpassphrase first.
Definition: protocol.h:101
@ RPC_MISC_ERROR
General application defined errors.
Definition: protocol.h:65
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:69
@ RPC_WALLET_ERROR
Wallet errors.
Definition: protocol.h:97
@ RPC_WALLET_ALREADY_LOADED
This same wallet is already loaded.
Definition: protocol.h:108
@ RPC_WALLET_NOT_FOUND
Invalid wallet specified.
Definition: protocol.h:106
@ RPC_DESERIALIZATION_ERROR
Error parsing or validating structure in raw format.
Definition: protocol.h:71
@ RPC_INVALID_ADDRESS_OR_KEY
Invalid address or key.
Definition: protocol.h:67
std::vector< uint32_t > ParsePathBIP32(const std::string &path)
Parse BIP32 path.
Definition: util.cpp:1381
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:189
std::string HelpExampleRpcNamed(const std::string &methodname, const RPCArgList &args)
Definition: util.cpp:213
void PushWarnings(const UniValue &warnings, UniValue &obj)
Push warning messages to an RPC "warnings" field as a JSON array of strings.
Definition: util.cpp:1401
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:207
const std::string UNIX_EPOCH_TIME
String used to describe UNIX epoch time in documentation, factored out to a constant for consistency.
Definition: util.cpp:49
std::string HelpExampleCliNamed(const std::string &methodname, const RPCArgList &args)
Definition: util.cpp:194
std::basic_string< char, std::char_traits< char >, secure_allocator< char > > SecureString
Definition: secure.h:53
Definition: key.h:232
CPubKey pubkey
Definition: pubkey.h:348
A mutable version of CTransaction.
Definition: transaction.h:372
std::vector< CTxOut > vout
Definition: transaction.h:374
Txid GetHash() const
Compute the hash of this CMutableTransaction.
Definition: transaction.cpp:69
std::vector< CTxIn > vin
Definition: transaction.h:373
@ STR_HEX
Special type that is a STR with only hex chars.
@ OBJ_NAMED_PARAMS
Special type that behaves almost exactly like OBJ, defining an options object with a list of pre-defi...
std::string DefaultHint
Hint for default value.
Definition: util.h:220
@ OMITTED
Optional argument for which the default value is omitted from help text for one of two reasons:
@ NO
Required arg.
@ NUM_TIME
Special numeric to denote unix epoch time.
@ STR_AMOUNT
Special string to represent a floating point amount.
Bilingual messages:
Definition: translation.h:24
bool require_existing
Definition: db.h:169
SecureString create_passphrase
Definition: db.h:173
uint64_t create_flags
Definition: db.h:172
WalletContext struct containing references to state shared between CWallet instances,...
Definition: context.h:36
ArgsManager * args
Definition: context.h:39
#define LOCK(cs)
Definition: sync.h:268
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:82