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_io.h>
13#include <rpc/server.h>
14#include <rpc/util.h>
15#include <univalue.h>
16#include <util/translation.h>
17#include <wallet/context.h>
18#include <wallet/receive.h>
19#include <wallet/rpc/util.h>
20#include <wallet/wallet.h>
21#include <wallet/walletutil.h>
22
23#include <optional>
24#include <string_view>
25
26
27namespace wallet {
28
29static const std::map<uint64_t, std::string> WALLET_FLAG_CAVEATS{
31 "You need to rescan the blockchain in order to correctly mark used "
32 "destinations in the past. Until this is done, some destinations may "
33 "be considered unused, even if the opposite is the case."},
34};
35
37{
38 return RPCMethod{"getwalletinfo",
39 "Returns an object containing various wallet state info.\n",
40 {},
43 {
44 {
45 {RPCResult::Type::STR, "walletname", "the wallet name"},
46 {RPCResult::Type::NUM, "walletversion", "(DEPRECATED) only related to unsupported legacy wallet, returns the latest version 169900 for backwards compatibility"},
47 {RPCResult::Type::STR, "format", "the database format (only sqlite)"},
48 {RPCResult::Type::NUM, "txcount", "the total number of transactions in the wallet"},
49 {RPCResult::Type::NUM, "keypoolsize", "how many new keys are pre-generated (only counts external keys)"},
50 {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)"},
51 {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)"},
52 {RPCResult::Type::BOOL, "private_keys_enabled", "false if privatekeys are disabled for this wallet (enforced watch-only wallet)"},
53 {RPCResult::Type::BOOL, "avoid_reuse", "whether this wallet tracks clean/dirty coins in terms of reuse"},
54 {RPCResult::Type::OBJ, "scanning", "current scanning details, or false if no scan is in progress",
55 {
56 {RPCResult::Type::NUM, "duration", "elapsed seconds since scan start"},
57 {RPCResult::Type::NUM, "progress", "scanning progress percentage [0.0, 1.0]"},
58 }, {.skip_type_check=true}, },
59 {RPCResult::Type::BOOL, "descriptors", "whether this wallet uses descriptors for output script management"},
60 {RPCResult::Type::BOOL, "external_signer", "whether this wallet is configured to use an external signer such as a hardware wallet"},
61 {RPCResult::Type::BOOL, "blank", "Whether this wallet intentionally does not contain any keys, scripts, or descriptors"},
62 {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."},
63 {RPCResult::Type::ARR, "flags", "The flags currently set on the wallet",
64 {
65 {RPCResult::Type::STR, "flag", "The name of the flag"},
66 }},
68 }},
69 },
71 HelpExampleCli("getwalletinfo", "")
72 + HelpExampleRpc("getwalletinfo", "")
73 },
74 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
75{
76 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
77 if (!pwallet) return UniValue::VNULL;
78
79 // Make sure the results are valid at least up to the most recent block
80 // the user could have gotten from another RPC command prior to now
81 pwallet->BlockUntilSyncedToCurrentChain();
82
83 LOCK(pwallet->cs_wallet);
84
86
87 const int latest_legacy_wallet_minversion{169900};
88
89 size_t kpExternalSize = pwallet->KeypoolCountExternalKeys();
90 obj.pushKV("walletname", pwallet->GetName());
91 obj.pushKV("walletversion", latest_legacy_wallet_minversion);
92 obj.pushKV("format", pwallet->GetDatabase().Format());
93 obj.pushKV("txcount", pwallet->mapWallet.size());
94 obj.pushKV("keypoolsize", kpExternalSize);
95 obj.pushKV("keypoolsize_hd_internal", pwallet->GetKeyPoolSize() - kpExternalSize);
96
97 if (pwallet->HasEncryptionKeys()) {
98 obj.pushKV("unlocked_until", pwallet->nRelockTime);
99 }
100 obj.pushKV("private_keys_enabled", !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
101 obj.pushKV("avoid_reuse", pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE));
102 if (pwallet->IsScanning()) {
103 UniValue scanning(UniValue::VOBJ);
104 scanning.pushKV("duration", Ticks<std::chrono::seconds>(pwallet->ScanningDuration()));
105 scanning.pushKV("progress", pwallet->ScanningProgress());
106 obj.pushKV("scanning", std::move(scanning));
107 } else {
108 obj.pushKV("scanning", false);
109 }
110 obj.pushKV("descriptors", pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
111 obj.pushKV("external_signer", pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER));
112 obj.pushKV("blank", pwallet->IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET));
113 if (int64_t birthtime = pwallet->GetBirthTime(); birthtime != UNKNOWN_TIME) {
114 obj.pushKV("birthtime", birthtime);
115 }
116
117 // Push known flags
119 uint64_t wallet_flags = pwallet->GetWalletFlags();
120 for (uint64_t i = 0; i < 64; ++i) {
121 uint64_t flag = uint64_t{1} << i;
122 if (flag & wallet_flags) {
123 if (flag & KNOWN_WALLET_FLAGS) {
124 flags.push_back(WALLET_FLAG_TO_STRING.at(WalletFlags{flag}));
125 } else {
126 flags.push_back(strprintf("unknown_flag_%u", i));
127 }
128 }
129 }
130 obj.pushKV("flags", flags);
131
132 AppendLastProcessedBlock(obj, *pwallet);
133 return obj;
134},
135 };
136}
137
139{
140 return RPCMethod{"listwalletdir",
141 "Returns a list of wallets in the wallet directory.\n",
142 {},
143 RPCResult{
144 RPCResult::Type::OBJ, "", "",
145 {
146 {RPCResult::Type::ARR, "wallets", "",
147 {
148 {RPCResult::Type::OBJ, "", "",
149 {
150 {RPCResult::Type::STR, "name", "The wallet name"},
151 {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to loading the wallet.",
152 {
153 {RPCResult::Type::STR, "", ""},
154 }},
155 }},
156 }},
157 }
158 },
160 HelpExampleCli("listwalletdir", "")
161 + HelpExampleRpc("listwalletdir", "")
162 },
163 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
164{
165 UniValue wallets(UniValue::VARR);
166 for (const auto& [path, db_type] : ListDatabases(GetWalletDir())) {
168 wallet.pushKV("name", path.utf8string());
169 UniValue warnings(UniValue::VARR);
170 if (db_type == "bdb") {
171 warnings.push_back("This wallet is a legacy wallet and will need to be migrated with migratewallet before it can be loaded");
172 }
173 wallet.pushKV("warnings", warnings);
174 wallets.push_back(std::move(wallet));
175 }
176
177 UniValue result(UniValue::VOBJ);
178 result.pushKV("wallets", std::move(wallets));
179 return result;
180},
181 };
182}
183
185{
186 return RPCMethod{"listwallets",
187 "Returns a list of currently loaded wallets.\n"
188 "For full information on the wallet, use \"getwalletinfo\"\n",
189 {},
190 RPCResult{
191 RPCResult::Type::ARR, "", "",
192 {
193 {RPCResult::Type::STR, "walletname", "the wallet name"},
194 }
195 },
197 HelpExampleCli("listwallets", "")
198 + HelpExampleRpc("listwallets", "")
199 },
200 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
201{
203
204 WalletContext& context = EnsureWalletContext(request.context);
205 for (const std::shared_ptr<CWallet>& wallet : GetWallets(context)) {
206 LOCK(wallet->cs_wallet);
207 obj.push_back(wallet->GetName());
208 }
209
210 return obj;
211},
212 };
213}
214
216{
217 return RPCMethod{
218 "loadwallet",
219 "Loads a wallet from a wallet file or directory."
220 "\nNote that all wallet command-line options used when starting bitcoind will be"
221 "\napplied to the new wallet.\n",
222 {
223 {"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."},
224 {"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."},
225 },
226 RPCResult{
227 RPCResult::Type::OBJ, "", "",
228 {
229 {RPCResult::Type::STR, "name", "The wallet name if loaded successfully."},
230 {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to loading the wallet.",
231 {
232 {RPCResult::Type::STR, "", ""},
233 }},
234 }
235 },
237 "\nLoad wallet from the wallet dir:\n"
238 + HelpExampleCli("loadwallet", "\"walletname\"")
239 + HelpExampleRpc("loadwallet", "\"walletname\"")
240 + "\nLoad wallet using absolute path (Unix):\n"
241 + HelpExampleCli("loadwallet", "\"/path/to/walletname/\"")
242 + HelpExampleRpc("loadwallet", "\"/path/to/walletname/\"")
243 + "\nLoad wallet using absolute path (Windows):\n"
244 + HelpExampleCli("loadwallet", "\"DriveLetter:\\path\\to\\walletname\\\"")
245 + HelpExampleRpc("loadwallet", "\"DriveLetter:\\path\\to\\walletname\\\"")
246 },
247 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
248{
249 WalletContext& context = EnsureWalletContext(request.context);
250 const std::string name(request.params[0].get_str());
251
252 DatabaseOptions options;
253 DatabaseStatus status;
254 ReadDatabaseArgs(*context.args, options);
255 options.require_existing = true;
256 bilingual_str error;
257 std::vector<bilingual_str> warnings;
258 std::optional<bool> load_on_start = request.params[1].isNull() ? std::nullopt : std::optional<bool>(request.params[1].get_bool());
259
260 {
261 LOCK(context.wallets_mutex);
262 if (std::any_of(context.wallets.begin(), context.wallets.end(), [&name](const auto& wallet) { return wallet->GetName() == name; })) {
263 throw JSONRPCError(RPC_WALLET_ALREADY_LOADED, "Wallet \"" + name + "\" is already loaded.");
264 }
265 }
266
267 std::shared_ptr<CWallet> const wallet = LoadWallet(context, name, load_on_start, options, status, error, warnings);
268
269 HandleWalletError(wallet, status, error);
270
272 obj.pushKV("name", wallet->GetName());
273 PushWarnings(warnings, obj);
274
275 return obj;
276},
277 };
278}
279
281{
282 std::string flags;
283 for (auto& it : STRING_TO_WALLET_FLAG)
284 if (it.second & MUTABLE_WALLET_FLAGS)
285 flags += (flags == "" ? "" : ", ") + it.first;
286
287 return RPCMethod{
288 "setwalletflag",
289 "Change the state of the given wallet flag for a wallet.\n",
290 {
291 {"flag", RPCArg::Type::STR, RPCArg::Optional::NO, "The name of the flag to change. Current available flags: " + flags},
292 {"value", RPCArg::Type::BOOL, RPCArg::Default{true}, "The new state."},
293 },
294 RPCResult{
295 RPCResult::Type::OBJ, "", "",
296 {
297 {RPCResult::Type::STR, "flag_name", "The name of the flag that was modified"},
298 {RPCResult::Type::BOOL, "flag_state", "The new state of the flag"},
299 {RPCResult::Type::STR, "warnings", /*optional=*/true, "Any warnings associated with the change"},
300 }
301 },
303 HelpExampleCli("setwalletflag", "avoid_reuse")
304 + HelpExampleRpc("setwalletflag", "\"avoid_reuse\"")
305 },
306 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
307{
308 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
309 if (!pwallet) return UniValue::VNULL;
310
311 std::string flag_str = request.params[0].get_str();
312 bool value = request.params[1].isNull() || request.params[1].get_bool();
313
314 if (!STRING_TO_WALLET_FLAG.contains(flag_str)) {
315 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Unknown wallet flag: %s", flag_str));
316 }
317
318 auto flag = STRING_TO_WALLET_FLAG.at(flag_str);
319
320 if (!(flag & MUTABLE_WALLET_FLAGS)) {
321 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is immutable: %s", flag_str));
322 }
323
325
326 if (pwallet->IsWalletFlagSet(flag) == value) {
327 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is already set to %s: %s", value ? "true" : "false", flag_str));
328 }
329
330 res.pushKV("flag_name", flag_str);
331 res.pushKV("flag_state", value);
332
333 if (value) {
334 pwallet->SetWalletFlag(flag);
335 } else {
336 pwallet->UnsetWalletFlag(flag);
337 }
338
339 if (flag && value && WALLET_FLAG_CAVEATS.contains(flag)) {
340 res.pushKV("warnings", WALLET_FLAG_CAVEATS.at(flag));
341 }
342
343 return res;
344},
345 };
346}
347
349{
350 return RPCMethod{
351 "createwallet",
352 "Creates and loads a new wallet.\n",
353 {
354 {"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."},
355 {"disable_private_keys", RPCArg::Type::BOOL, RPCArg::Default{false}, "Disable the possibility of private keys (only watchonlys are possible in this mode)."},
356 {"blank", RPCArg::Type::BOOL, RPCArg::Default{false}, "Create a blank wallet. A blank wallet has no keys."},
357 {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."},
358 {"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."},
359 {"descriptors", RPCArg::Type::BOOL, RPCArg::Default{true}, "If set, must be \"true\""},
360 {"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."},
361 {"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."},
362 },
363 RPCResult{
364 RPCResult::Type::OBJ, "", "",
365 {
366 {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."},
367 {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to creating and loading the wallet.",
368 {
369 {RPCResult::Type::STR, "", ""},
370 }},
371 }
372 },
374 HelpExampleCli("createwallet", "\"testwallet\"")
375 + HelpExampleRpc("createwallet", "\"testwallet\"")
376 + HelpExampleCliNamed("createwallet", {{"wallet_name", "descriptors"}, {"avoid_reuse", true}, {"load_on_startup", true}})
377 + HelpExampleRpcNamed("createwallet", {{"wallet_name", "descriptors"}, {"avoid_reuse", true}, {"load_on_startup", true}})
378 },
379 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
380{
381 WalletContext& context = EnsureWalletContext(request.context);
382 uint64_t flags = 0;
383 if (!request.params[1].isNull() && request.params[1].get_bool()) {
385 }
386
387 if (!request.params[2].isNull() && request.params[2].get_bool()) {
389 }
390 SecureString passphrase;
391 passphrase.reserve(100);
392 std::vector<bilingual_str> warnings;
393 if (!request.params[3].isNull()) {
394 passphrase = std::string_view{request.params[3].get_str()};
395 if (passphrase.empty()) {
396 // Empty string means unencrypted
397 warnings.emplace_back(Untranslated("Empty string given as passphrase, wallet will not be encrypted."));
398 }
399 }
400
401 if (!request.params[4].isNull() && request.params[4].get_bool()) {
403 }
405 if (!self.Arg<bool>("descriptors")) {
406 throw JSONRPCError(RPC_WALLET_ERROR, "descriptors argument must be set to \"true\"; it is no longer possible to create a legacy wallet.");
407 }
408 if (!request.params[7].isNull() && request.params[7].get_bool()) {
409#ifdef ENABLE_EXTERNAL_SIGNER
411#else
412 throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without external signing support (required for external signing)");
413#endif
414 }
415
416 DatabaseOptions options;
417 DatabaseStatus status;
418 ReadDatabaseArgs(*context.args, options);
419 options.require_create = true;
420 options.create_flags = flags;
421 options.create_passphrase = passphrase;
422 bilingual_str error;
423 std::optional<bool> load_on_start = request.params[6].isNull() ? std::nullopt : std::optional<bool>(request.params[6].get_bool());
424 const std::shared_ptr<CWallet> wallet = CreateWallet(context, request.params[0].get_str(), load_on_start, options, status, error, warnings);
425 HandleWalletError(wallet, status, error);
426
428 obj.pushKV("name", wallet->GetName());
429 PushWarnings(warnings, obj);
430
431 return obj;
432},
433 };
434}
435
437{
438 return RPCMethod{"unloadwallet",
439 "Unloads the wallet referenced by the request endpoint or the wallet_name argument.\n"
440 "If both are specified, they must be identical.",
441 {
442 {"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."},
443 {"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."},
444 },
446 {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to unloading the wallet.",
447 {
448 {RPCResult::Type::STR, "", ""},
449 }},
450 }},
452 HelpExampleCli("unloadwallet", "wallet_name")
453 + HelpExampleRpc("unloadwallet", "wallet_name")
454 },
455 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
456{
457 const std::string wallet_name{EnsureUniqueWalletName(request, self.MaybeArg<std::string_view>("wallet_name"))};
458
459 WalletContext& context = EnsureWalletContext(request.context);
460 std::shared_ptr<CWallet> wallet = GetWallet(context, wallet_name);
461 if (!wallet) {
462 throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
463 }
464
465 std::vector<bilingual_str> warnings;
466 {
467 WalletRescanReserver reserver(*wallet);
468 if (!reserver.reserve()) {
469 throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
470 }
471
472 // Release the "main" shared pointer and prevent further notifications.
473 // Note that any attempt to load the same wallet would fail until the wallet
474 // is destroyed (see CheckUniqueFileid).
475 std::optional<bool> load_on_start{self.MaybeArg<bool>("load_on_startup")};
476 if (!RemoveWallet(context, wallet, load_on_start, warnings)) {
477 throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded");
478 }
479 }
480
481 WaitForDeleteWallet(std::move(wallet));
482
483 UniValue result(UniValue::VOBJ);
484 PushWarnings(warnings, result);
485
486 return result;
487},
488 };
489}
490
492{
493 return RPCMethod{
494 "simulaterawtransaction",
495 "Calculate the balance change resulting in the signing and broadcasting of the given transaction(s).\n",
496 {
497 {"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "An array of hex strings of raw transactions.\n",
498 {
500 },
501 },
503 {
504 {"include_watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
505 },
506 },
507 },
508 RPCResult{
509 RPCResult::Type::OBJ, "", "",
510 {
511 {RPCResult::Type::STR_AMOUNT, "balance_change", "The wallet balance change (negative means decrease)."},
512 }
513 },
515 HelpExampleCli("simulaterawtransaction", "[\"myhex\"]")
516 + HelpExampleRpc("simulaterawtransaction", "[\"myhex\"]")
517 },
518 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
519{
520 const std::shared_ptr<const CWallet> rpc_wallet = GetWalletForJSONRPCRequest(request);
521 if (!rpc_wallet) return UniValue::VNULL;
522 const CWallet& wallet = *rpc_wallet;
523
524 LOCK(wallet.cs_wallet);
525
526 const auto& txs = request.params[0].get_array();
527 CAmount changes{0};
528 std::map<COutPoint, CAmount> new_utxos; // UTXO:s that were made available in transaction array
529 std::set<COutPoint> spent;
530
531 for (size_t i = 0; i < txs.size(); ++i) {
533 if (!DecodeHexTx(mtx, txs[i].get_str(), /*try_no_witness=*/ true, /*try_witness=*/ true)) {
534 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Transaction hex string decoding failure.");
535 }
536
537 // Fetch previous transactions (inputs)
538 std::map<COutPoint, Coin> coins;
539 for (const CTxIn& txin : mtx.vin) {
540 coins[txin.prevout]; // Create empty map entry keyed by prevout.
541 }
542 wallet.chain().findCoins(coins);
543
544 // Fetch debit; we are *spending* these; if the transaction is signed and
545 // broadcast, we will lose everything in these
546 for (const auto& txin : mtx.vin) {
547 const auto& outpoint = txin.prevout;
548 if (spent.contains(outpoint)) {
549 throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction(s) are spending the same output more than once");
550 }
551 if (new_utxos.contains(outpoint)) {
552 changes -= new_utxos.at(outpoint);
553 new_utxos.erase(outpoint);
554 } else {
555 if (coins.at(outpoint).IsSpent()) {
556 throw JSONRPCError(RPC_INVALID_PARAMETER, "One or more transaction inputs are missing or have been spent already");
557 }
558 changes -= wallet.GetDebit(txin);
559 }
560 spent.insert(outpoint);
561 }
562
563 // Iterate over outputs; we are *receiving* these, if the wallet considers
564 // them "mine"; if the transaction is signed and broadcast, we will receive
565 // everything in these
566 // Also populate new_utxos in case these are spent in later transactions
567
568 const auto& hash = mtx.GetHash();
569 for (size_t i = 0; i < mtx.vout.size(); ++i) {
570 const auto& txout = mtx.vout[i];
571 bool is_mine = wallet.IsMine(txout);
572 changes += new_utxos[COutPoint(hash, i)] = is_mine ? txout.nValue : 0;
573 }
574 }
575
576 UniValue result(UniValue::VOBJ);
577 result.pushKV("balance_change", ValueFromAmount(changes));
578
579 return result;
580}
581 };
582}
583
585{
586 return RPCMethod{
587 "migratewallet",
588 "Migrate the wallet to a descriptor wallet.\n"
589 "A new wallet backup will need to be made.\n"
590 "\nThe migration process will create a backup of the wallet before migrating. This backup\n"
591 "file will be named <wallet name>-<timestamp>.legacy.bak and can be found in the directory\n"
592 "for this wallet. In the event of an incorrect migration, the backup can be restored using restorewallet."
593 "\nEncrypted wallets must have the passphrase provided as an argument to this call.\n"
594 "\nThis RPC may take a long time to complete. Increasing the RPC client timeout is recommended.",
595 {
596 {"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."},
597 {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "The wallet passphrase"},
598 },
599 RPCResult{
600 RPCResult::Type::OBJ, "", "",
601 {
602 {RPCResult::Type::STR, "wallet_name", "The name of the primary migrated wallet"},
603 {RPCResult::Type::STR, "watchonly_name", /*optional=*/true, "The name of the migrated wallet containing the watchonly scripts"},
604 {RPCResult::Type::STR, "solvables_name", /*optional=*/true, "The name of the migrated wallet containing solvable but not watched scripts"},
605 {RPCResult::Type::STR, "backup_path", "The location of the backup of the original wallet"},
606 }
607 },
609 HelpExampleCli("migratewallet", "")
610 + HelpExampleRpc("migratewallet", "")
611 },
612 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
613 {
614 const std::string wallet_name{EnsureUniqueWalletName(request, self.MaybeArg<std::string_view>("wallet_name"))};
615
616 SecureString wallet_pass;
617 wallet_pass.reserve(100);
618 if (!request.params[1].isNull()) {
619 wallet_pass = std::string_view{request.params[1].get_str()};
620 }
621
622 WalletContext& context = EnsureWalletContext(request.context);
623 util::Result<MigrationResult> res = MigrateLegacyToDescriptor(wallet_name, wallet_pass, context);
624 if (!res) {
625 throw JSONRPCError(RPC_WALLET_ERROR, util::ErrorString(res).original);
626 }
627
629 r.pushKV("wallet_name", res->wallet_name);
630 if (res->watchonly_wallet) {
631 r.pushKV("watchonly_name", res->watchonly_wallet->GetName());
632 }
633 if (res->solvables_wallet) {
634 r.pushKV("solvables_name", res->solvables_wallet->GetName());
635 }
636 r.pushKV("backup_path", res->backup_path.utf8string());
637
638 return r;
639 },
640 };
641}
642
644{
645 return RPCMethod{
646 "gethdkeys",
647 "List all BIP 32 HD keys in the wallet and which descriptors use them.\n",
648 {
650 {"active_only", RPCArg::Type::BOOL, RPCArg::Default{false}, "Show the keys for only active descriptors"},
651 {"private", RPCArg::Type::BOOL, RPCArg::Default{false}, "Show private keys"}
652 }},
653 },
655 {
656 {RPCResult::Type::OBJ, "", "", {
657 {RPCResult::Type::STR, "xpub", "The extended public key"},
658 {RPCResult::Type::BOOL, "has_private", "Whether the wallet has the private key for this xpub"},
659 {RPCResult::Type::STR, "xprv", /*optional=*/true, "The extended private key if \"private\" is true"},
660 {RPCResult::Type::ARR, "descriptors", "Array of descriptor objects that use this HD key",
661 {
662 {RPCResult::Type::OBJ, "", "", {
663 {RPCResult::Type::STR, "desc", "Descriptor string public representation"},
664 {RPCResult::Type::BOOL, "active", "Whether this descriptor is currently used to generate new addresses"},
665 }},
666 }},
667 }},
668 }
669 }},
671 HelpExampleCli("gethdkeys", "") + HelpExampleRpc("gethdkeys", "")
672 + HelpExampleCliNamed("gethdkeys", {{"active_only", "true"}, {"private", "true"}}) + HelpExampleRpcNamed("gethdkeys", {{"active_only", "true"}, {"private", "true"}})
673 },
674 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
675 {
676 const std::shared_ptr<const CWallet> wallet = GetWalletForJSONRPCRequest(request);
677 if (!wallet) return UniValue::VNULL;
678
679 LOCK(wallet->cs_wallet);
680
681 UniValue options{request.params[0].isNull() ? UniValue::VOBJ : request.params[0]};
682 const bool active_only{options.exists("active_only") ? options["active_only"].get_bool() : false};
683 const bool priv{options.exists("private") ? options["private"].get_bool() : false};
684 if (priv) {
686 }
687
688
689 std::set<ScriptPubKeyMan*> spkms;
690 if (active_only) {
691 spkms = wallet->GetActiveScriptPubKeyMans();
692 } else {
693 spkms = wallet->GetAllScriptPubKeyMans();
694 }
695
696 std::map<CExtPubKey, std::set<std::tuple<std::string, bool, bool>>> wallet_xpubs;
697 std::map<CExtPubKey, CExtKey> wallet_xprvs;
698 for (auto* spkm : spkms) {
699 auto* desc_spkm{dynamic_cast<DescriptorScriptPubKeyMan*>(spkm)};
700 CHECK_NONFATAL(desc_spkm);
701 LOCK(desc_spkm->cs_desc_man);
702 WalletDescriptor w_desc = desc_spkm->GetWalletDescriptor();
703
704 // Retrieve the pubkeys from the descriptor
705 std::set<CPubKey> desc_pubkeys;
706 std::set<CExtPubKey> desc_xpubs;
707 w_desc.descriptor->GetPubKeys(desc_pubkeys, desc_xpubs);
708 for (const CExtPubKey& xpub : desc_xpubs) {
709 std::string desc_str;
710 bool ok = desc_spkm->GetDescriptorString(desc_str, /*priv=*/false);
711 CHECK_NONFATAL(ok);
712 wallet_xpubs[xpub].emplace(desc_str, wallet->IsActiveScriptPubKeyMan(*spkm), desc_spkm->HasPrivKey(xpub.pubkey.GetID()));
713 if (std::optional<CKey> key = priv ? desc_spkm->GetKey(xpub.pubkey.GetID()) : std::nullopt) {
714 wallet_xprvs[xpub] = CExtKey(xpub, *key);
715 }
716 }
717 }
718
719 UniValue response(UniValue::VARR);
720 for (const auto& [xpub, descs] : wallet_xpubs) {
721 bool has_xprv = false;
722 UniValue descriptors(UniValue::VARR);
723 for (const auto& [desc, active, has_priv] : descs) {
725 d.pushKV("desc", desc);
726 d.pushKV("active", active);
727 has_xprv |= has_priv;
728
729 descriptors.push_back(std::move(d));
730 }
731 UniValue xpub_info(UniValue::VOBJ);
732 xpub_info.pushKV("xpub", EncodeExtPubKey(xpub));
733 xpub_info.pushKV("has_private", has_xprv);
734 if (priv && has_xprv) {
735 xpub_info.pushKV("xprv", EncodeExtKey(wallet_xprvs.at(xpub)));
736 }
737 xpub_info.pushKV("descriptors", std::move(descriptors));
738
739 response.push_back(std::move(xpub_info));
740 }
741
742 return response;
743 },
744 };
745}
746
748{
749 return RPCMethod{"createwalletdescriptor",
750 "Creates the wallet's descriptor for the given address type. "
751 "The address type must be one that the wallet does not already have a descriptor for."
753 {
754 {"type", RPCArg::Type::STR, RPCArg::Optional::NO, "The address type the descriptor will produce. Options are " + FormatAllOutputTypes() + "."},
756 {"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)"},
757 {"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"},
758 }},
759 },
760 RPCResult{
761 RPCResult::Type::OBJ, "", "",
762 {
763 {RPCResult::Type::ARR, "descs", "The public descriptors that were added to the wallet",
764 {{RPCResult::Type::STR, "", ""}}
765 }
766 },
767 },
769 HelpExampleCli("createwalletdescriptor", "bech32m")
770 + HelpExampleRpc("createwalletdescriptor", "bech32m")
771 },
772 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
773 {
774 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
775 if (!pwallet) return UniValue::VNULL;
776
777 std::optional<OutputType> output_type = ParseOutputType(request.params[0].get_str());
778 if (!output_type) {
779 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[0].get_str()));
780 }
781
782 UniValue options{request.params[1].isNull() ? UniValue::VOBJ : request.params[1]};
783 UniValue internal_only{options["internal"]};
784 UniValue hdkey{options["hdkey"]};
785
786 std::vector<bool> internals;
787 if (internal_only.isNull()) {
788 internals.push_back(false);
789 internals.push_back(true);
790 } else {
791 internals.push_back(internal_only.get_bool());
792 }
793
794 LOCK(pwallet->cs_wallet);
795 EnsureWalletIsUnlocked(*pwallet);
796
797 CExtPubKey xpub;
798 if (hdkey.isNull()) {
799 std::set<CExtPubKey> active_xpubs = pwallet->GetActiveHDPubKeys();
800 if (active_xpubs.size() != 1) {
801 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to determine which HD key to use from active descriptors. Please specify with 'hdkey'");
802 }
803 xpub = *active_xpubs.begin();
804 } else {
805 xpub = DecodeExtPubKey(hdkey.get_str());
806 if (!xpub.pubkey.IsValid()) {
807 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to parse HD key. Please provide a valid xpub");
808 }
809 }
810
811 std::optional<CKey> key = pwallet->GetKey(xpub.pubkey.GetID());
812 if (!key) {
813 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Private key for %s is not known", EncodeExtPubKey(xpub)));
814 }
815 CExtKey active_hdkey(xpub, *key);
816
817 std::vector<std::reference_wrapper<DescriptorScriptPubKeyMan>> spkms;
818 WalletBatch batch{pwallet->GetDatabase()};
819 for (bool internal : internals) {
820 WalletDescriptor w_desc = GenerateWalletDescriptor(xpub, *output_type, internal);
821 uint256 w_id = DescriptorID(*w_desc.descriptor);
822 if (!pwallet->GetScriptPubKeyMan(w_id)) {
823 spkms.emplace_back(pwallet->SetupDescriptorScriptPubKeyMan(batch, active_hdkey, *output_type, internal));
824 }
825 }
826 if (spkms.empty()) {
827 throw JSONRPCError(RPC_WALLET_ERROR, "Descriptor already exists");
828 }
829
830 // Fetch each descspkm from the wallet in order to get the descriptor strings
832 for (const auto& spkm : spkms) {
833 std::string desc_str;
834 bool ok = spkm.get().GetDescriptorString(desc_str, false);
835 CHECK_NONFATAL(ok);
836 descs.push_back(desc_str);
837 }
839 out.pushKV("descs", std::move(descs));
840 return out;
841 }
842 };
843}
844
846{
847 return RPCMethod{
848 "addhdkey",
849 "Add a BIP 32 HD key to the wallet that can be used with 'createwalletdescriptor'\n",
850 {
851 {"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."},
852 },
853 RPCResult{
854 RPCResult::Type::OBJ, "", "",
855 {
856 {RPCResult::Type::STR, "xpub", "The xpub of the HD key that was added to the wallet"}
857 },
858 },
860 HelpExampleCli("addhdkey", "xprv") + HelpExampleRpc("addhdkey", "xprv")
861 },
862 [&](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
863 {
864 std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
865 if (!wallet) return UniValue::VNULL;
866
867 if (wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
868 throw JSONRPCError(RPC_WALLET_ERROR, "addhdkey is not available for wallets without private keys");
869 }
870
872
873 CExtKey hdkey;
874 if (request.params[0].isNull()) {
875 CKey seed_key = GenerateRandomKey();
876 hdkey.SetSeed(seed_key);
877 } else {
878 hdkey = DecodeExtKey(request.params[0].get_str());
879 if (!hdkey.key.IsValid()) {
880 // Check if the user gave us an xpub and give a more descriptive error if so
881 CExtPubKey xpub = DecodeExtPubKey(request.params[0].get_str());
882 if (xpub.pubkey.IsValid()) {
883 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Extended public key (xpub) provided, but extended private key (xprv) is required");
884 } else {
885 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Could not parse HD key");
886 }
887 }
888 }
889
890 LOCK(wallet->cs_wallet);
891 std::string desc_str = "unused(" + EncodeExtKey(hdkey) + ")";
893 std::string error;
894 std::vector<std::unique_ptr<Descriptor>> descs = Parse(desc_str, keys, error, false);
895 CHECK_NONFATAL(!descs.empty());
896 WalletDescriptor w_desc(std::move(descs.at(0)), GetTime(), 0, 0, 0);
897 if (wallet->GetDescriptorScriptPubKeyMan(w_desc) != nullptr) {
898 throw JSONRPCError(RPC_WALLET_ERROR, "HD key already exists");
899 }
900
901 auto spkm = wallet->AddWalletDescriptor(w_desc, keys, /*label=*/"", /*internal=*/false);
902 if (!spkm) {
903 throw JSONRPCError(RPC_WALLET_ERROR, util::ErrorString(spkm).original);
904 }
905
906 UniValue response(UniValue::VOBJ);
907 const DescriptorScriptPubKeyMan& desc_spkm = spkm->get();
908 LOCK(desc_spkm.cs_desc_man);
909 std::set<CPubKey> pubkeys;
910 std::set<CExtPubKey> extpubs;
911 desc_spkm.GetWalletDescriptor().descriptor->GetPubKeys(pubkeys, extpubs);
912 CHECK_NONFATAL(pubkeys.size() == 0);
913 CHECK_NONFATAL(extpubs.size() == 1);
914 response.pushKV("xpub", EncodeExtPubKey(*extpubs.begin()));
915
916 return response;
917 },
918 };
919}
920
921// addresses
930#ifdef ENABLE_EXTERNAL_SIGNER
932#endif // ENABLE_EXTERNAL_SIGNER
933
934// backup
941
942// coins
950
951// encryption
956
957// spend
968
969// signmessage
971
972// transactions
981
982std::span<const CRPCCommand> GetWalletRPCCommands()
983{
984 static const CRPCCommand commands[]{
985 {"rawtransactions", &fundrawtransaction},
986 {"wallet", &abandontransaction},
987 {"wallet", &abortrescan},
988 {"wallet", &addhdkey},
989 {"wallet", &backupwallet},
990 {"wallet", &bumpfee},
991 {"wallet", &psbtbumpfee},
992 {"wallet", &createwallet},
993 {"wallet", &createwalletdescriptor},
994 {"wallet", &restorewallet},
995 {"wallet", &encryptwallet},
996 {"wallet", &getaddressesbylabel},
997 {"wallet", &getaddressinfo},
998 {"wallet", &getbalance},
999 {"wallet", &gethdkeys},
1000 {"wallet", &getnewaddress},
1001 {"wallet", &getrawchangeaddress},
1002 {"wallet", &getreceivedbyaddress},
1003 {"wallet", &getreceivedbylabel},
1004 {"wallet", &gettransaction},
1005 {"wallet", &getbalances},
1006 {"wallet", &getwalletinfo},
1007 {"wallet", &importdescriptors},
1008 {"wallet", &importprunedfunds},
1009 {"wallet", &keypoolrefill},
1010 {"wallet", &listaddressgroupings},
1011 {"wallet", &listdescriptors},
1012 {"wallet", &listlabels},
1013 {"wallet", &listlockunspent},
1014 {"wallet", &listreceivedbyaddress},
1015 {"wallet", &listreceivedbylabel},
1016 {"wallet", &listsinceblock},
1017 {"wallet", &listtransactions},
1018 {"wallet", &listunspent},
1019 {"wallet", &listwalletdir},
1020 {"wallet", &listwallets},
1021 {"wallet", &loadwallet},
1022 {"wallet", &lockunspent},
1023 {"wallet", &migratewallet},
1024 {"wallet", &removeprunedfunds},
1025 {"wallet", &rescanblockchain},
1026 {"wallet", &send},
1027 {"wallet", &sendmany},
1028 {"wallet", &sendtoaddress},
1029 {"wallet", &setlabel},
1030 {"wallet", &setwalletflag},
1031 {"wallet", &signmessage},
1032 {"wallet", &signrawtransactionwithwallet},
1033 {"wallet", &simulaterawtransaction},
1034 {"wallet", &sendall},
1035 {"wallet", &unloadwallet},
1036 {"wallet", &walletcreatefundedpsbt},
1037#ifdef ENABLE_EXTERNAL_SIGNER
1038 {"wallet", &walletdisplayaddress},
1039#endif // ENABLE_EXTERNAL_SIGNER
1040 {"wallet", &walletlock},
1041 {"wallet", &walletpassphrase},
1042 {"wallet", &walletpassphrasechange},
1043 {"wallet", &walletprocesspsbt},
1044 };
1045 return commands;
1046}
1047} // namespace wallet
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
int flags
Definition: bitcoin-tx.cpp:530
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:112
An encapsulated private key.
Definition: key.h:37
bool IsValid() const
Check whether this private key is valid.
Definition: key.h:125
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:158
bool IsValid() const
Definition: pubkey.h:183
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:490
auto Arg(std::string_view key) const
Helper to get a required or default-valued request argument.
Definition: util.h:458
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
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:309
WalletDescriptor GetWalletDescriptor() const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man)
Access to the wallet database.
Definition: walletdb.h:197
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:1090
bool reserve(bool with_passphrase=false)
Definition: wallet.h:1100
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:400
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
CKey GenerateRandomKey(bool compressed) noexcept
Definition: key.cpp:352
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:365
RPCMethod abortrescan()
RPCMethod gettransaction()
RPCMethod send()
Definition: spend.cpp:1178
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:491
RPCMethod fundrawtransaction()
Definition: spend.cpp:706
std::vector< std::shared_ptr< CWallet > > GetWallets(WalletContext &context)
Definition: wallet.cpp:195
RPCMethod listsinceblock()
static RPCMethod unloadwallet()
Definition: wallet.cpp:436
static const RPCResult RESULT_LAST_PROCESSED_BLOCK
Definition: util.h:30
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:322
RPCMethod gethdkeys()
Definition: wallet.cpp:643
RPCMethod listlockunspent()
Definition: coins.cpp:347
RPCMethod getreceivedbyaddress()
Definition: coins.cpp:80
static RPCMethod createwalletdescriptor()
Definition: wallet.cpp:747
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
util::Result< MigrationResult > MigrateLegacyToDescriptor(std::shared_ptr< CWallet > local_wallet, const SecureString &passphrase, WalletContext &context)
Requirement: The wallet provided to this function must be isolated, with no attachment to the node's ...
Definition: wallet.cpp:4315
static RPCMethod setwalletflag()
Definition: wallet.cpp:280
RPCMethod listtransactions()
RPCMethod getaddressinfo()
Definition: addresses.cpp:368
bool RemoveWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet, std::optional< bool > load_on_start)
Definition: wallet.cpp:189
WalletContext & EnsureWalletContext(const std::any &context)
Definition: util.cpp:92
RPCMethod removeprunedfunds()
Definition: backup.cpp:94
RPCMethod encryptwallet()
Definition: encrypt.cpp:221
RPCMethod lockunspent()
Definition: coins.cpp:214
fs::path GetWalletDir()
Get the path of the wallet directory.
Definition: walletutil.cpp:13
RPCMethod listreceivedbyaddress()
RPCMethod sendall()
Definition: spend.cpp:1302
RPCMethod walletdisplayaddress()
Definition: addresses.cpp:633
RPCMethod getbalance()
Definition: coins.cpp:164
RPCMethod listaddressgroupings()
Definition: addresses.cpp:157
RPCMethod importprunedfunds()
Definition: backup.cpp:39
static constexpr int64_t UNKNOWN_TIME
Constant representing an unknown spkm creation time.
RPCMethod getbalances()
Definition: coins.cpp:401
RPCMethod keypoolrefill()
Definition: addresses.cpp:218
RPCMethod walletlock()
Definition: encrypt.cpp:178
RPCMethod signrawtransactionwithwallet()
Definition: spend.cpp:841
RPCMethod listdescriptors()
Definition: backup.cpp:485
void AppendLastProcessedBlock(UniValue &entry, const CWallet &wallet)
Definition: util.cpp:156
RPCMethod walletprocesspsbt()
Definition: spend.cpp:1591
RPCMethod addhdkey()
Definition: wallet.cpp:845
RPCMethod psbtbumpfee()
Definition: spend.cpp:1176
RPCMethod getaddressesbylabel()
Definition: addresses.cpp:515
static RPCMethod migratewallet()
Definition: wallet.cpp:584
static constexpr uint64_t KNOWN_WALLET_FLAGS
Definition: wallet.h:149
RPCMethod bumpfee()
Definition: spend.cpp:1175
static RPCMethod loadwallet()
Definition: wallet.cpp:215
RPCMethod listunspent()
Definition: coins.cpp:456
RPCMethod signmessage()
Definition: signmessage.cpp:14
RPCMethod listlabels()
Definition: addresses.cpp:576
static const std::map< uint64_t, std::string > WALLET_FLAG_CAVEATS
Definition: wallet.cpp:29
static RPCMethod listwallets()
Definition: wallet.cpp:184
RPCMethod getreceivedbylabel()
Definition: coins.cpp:122
static RPCMethod getwalletinfo()
Definition: wallet.cpp:36
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:378
RPCMethod sendtoaddress()
Definition: spend.cpp:238
RPCMethod backupwallet()
Definition: backup.cpp:595
static RPCMethod listwalletdir()
Definition: wallet.cpp:138
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:255
RPCMethod sendmany()
Definition: spend.cpp:336
static const std::map< std::string, WalletFlags > STRING_TO_WALLET_FLAG
Definition: wallet.h:171
static constexpr uint64_t MUTABLE_WALLET_FLAGS
Definition: wallet.h:158
std::shared_ptr< CWallet > GetWallet(WalletContext &context, const std::string &name)
Definition: wallet.cpp:208
RPCMethod getnewaddress()
Definition: addresses.cpp:21
static RPCMethod createwallet()
Definition: wallet.cpp:348
std::span< const CRPCCommand > GetWalletRPCCommands()
Definition: wallet.cpp:982
static const std::map< WalletFlags, std::string > WALLET_FLAG_TO_STRING
Definition: wallet.h:161
RPCMethod restorewallet()
Definition: backup.cpp:630
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:49
@ RPC_MISC_ERROR
General application defined errors.
Definition: protocol.h:40
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:44
@ RPC_WALLET_ERROR
Wallet errors.
Definition: protocol.h:71
@ RPC_WALLET_ALREADY_LOADED
This same wallet is already loaded.
Definition: protocol.h:82
@ RPC_WALLET_NOT_FOUND
Invalid wallet specified.
Definition: protocol.h:80
@ RPC_DESERIALIZATION_ERROR
Error parsing or validating structure in raw format.
Definition: protocol.h:46
@ RPC_INVALID_ADDRESS_OR_KEY
Invalid address or key.
Definition: protocol.h:42
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:183
std::string HelpExampleRpcNamed(const std::string &methodname, const RPCArgList &args)
Definition: util.cpp:207
void PushWarnings(const UniValue &warnings, UniValue &obj)
Push warning messages to an RPC "warnings" field as a JSON array of strings.
Definition: util.cpp:1393
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:201
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:43
std::string HelpExampleCliNamed(const std::string &methodname, const RPCArgList &args)
Definition: util.cpp:188
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:229
CKey key
Definition: key.h:234
void SetSeed(std::span< const std::byte > seed)
Definition: key.cpp:368
CPubKey pubkey
Definition: pubkey.h:340
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: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: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
#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