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