Bitcoin Core  29.1.0
P2P Digital Currency
wallet.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2022 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 <core_io.h>
9 #include <key_io.h>
10 #include <rpc/server.h>
11 #include <rpc/util.h>
12 #include <util/translation.h>
13 #include <wallet/context.h>
14 #include <wallet/receive.h>
15 #include <wallet/rpc/wallet.h>
16 #include <wallet/rpc/util.h>
17 #include <wallet/wallet.h>
18 #include <wallet/walletutil.h>
19 
20 #include <optional>
21 
22 #include <univalue.h>
23 
24 
25 namespace wallet {
26 
27 static const std::map<uint64_t, std::string> WALLET_FLAG_CAVEATS{
29  "You need to rescan the blockchain in order to correctly mark used "
30  "destinations in the past. Until this is done, some destinations may "
31  "be considered unused, even if the opposite is the case."},
32 };
33 
35 bool HaveKey(const SigningProvider& wallet, const CKey& key)
36 {
37  CKey key2;
38  key2.Set(key.begin(), key.end(), !key.IsCompressed());
39  return wallet.HaveKey(key.GetPubKey().GetID()) || wallet.HaveKey(key2.GetPubKey().GetID());
40 }
41 
43 {
44  return RPCHelpMan{"getwalletinfo",
45  "Returns an object containing various wallet state info.\n",
46  {},
47  RPCResult{
48  RPCResult::Type::OBJ, "", "",
49  {
50  {
51  {RPCResult::Type::STR, "walletname", "the wallet name"},
52  {RPCResult::Type::NUM, "walletversion", "the wallet version"},
53  {RPCResult::Type::STR, "format", "the database format (bdb or sqlite)"},
54  {RPCResult::Type::STR_AMOUNT, "balance", "DEPRECATED. Identical to getbalances().mine.trusted"},
55  {RPCResult::Type::STR_AMOUNT, "unconfirmed_balance", "DEPRECATED. Identical to getbalances().mine.untrusted_pending"},
56  {RPCResult::Type::STR_AMOUNT, "immature_balance", "DEPRECATED. Identical to getbalances().mine.immature"},
57  {RPCResult::Type::NUM, "txcount", "the total number of transactions in the wallet"},
58  {RPCResult::Type::NUM_TIME, "keypoololdest", /*optional=*/true, "the " + UNIX_EPOCH_TIME + " of the oldest pre-generated key in the key pool. Legacy wallets only."},
59  {RPCResult::Type::NUM, "keypoolsize", "how many new keys are pre-generated (only counts external keys)"},
60  {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)"},
61  {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)"},
62  {RPCResult::Type::STR_AMOUNT, "paytxfee", "the transaction fee configuration, set in " + CURRENCY_UNIT + "/kvB"},
63  {RPCResult::Type::STR_HEX, "hdseedid", /*optional=*/true, "the Hash160 of the HD seed (only present when HD is enabled)"},
64  {RPCResult::Type::BOOL, "private_keys_enabled", "false if privatekeys are disabled for this wallet (enforced watch-only wallet)"},
65  {RPCResult::Type::BOOL, "avoid_reuse", "whether this wallet tracks clean/dirty coins in terms of reuse"},
66  {RPCResult::Type::OBJ, "scanning", "current scanning details, or false if no scan is in progress",
67  {
68  {RPCResult::Type::NUM, "duration", "elapsed seconds since scan start"},
69  {RPCResult::Type::NUM, "progress", "scanning progress percentage [0.0, 1.0]"},
70  }, /*skip_type_check=*/true},
71  {RPCResult::Type::BOOL, "descriptors", "whether this wallet uses descriptors for output script management"},
72  {RPCResult::Type::BOOL, "external_signer", "whether this wallet is configured to use an external signer such as a hardware wallet"},
73  {RPCResult::Type::BOOL, "blank", "Whether this wallet intentionally does not contain any keys, scripts, or descriptors"},
74  {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."},
76  }},
77  },
79  HelpExampleCli("getwalletinfo", "")
80  + HelpExampleRpc("getwalletinfo", "")
81  },
82  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
83 {
84  const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
85  if (!pwallet) return UniValue::VNULL;
86 
87  // Make sure the results are valid at least up to the most recent block
88  // the user could have gotten from another RPC command prior to now
89  pwallet->BlockUntilSyncedToCurrentChain();
90 
91  LOCK(pwallet->cs_wallet);
92 
94 
95  size_t kpExternalSize = pwallet->KeypoolCountExternalKeys();
96  const auto bal = GetBalance(*pwallet);
97  obj.pushKV("walletname", pwallet->GetName());
98  obj.pushKV("walletversion", pwallet->GetVersion());
99  obj.pushKV("format", pwallet->GetDatabase().Format());
100  obj.pushKV("balance", ValueFromAmount(bal.m_mine_trusted));
101  obj.pushKV("unconfirmed_balance", ValueFromAmount(bal.m_mine_untrusted_pending));
102  obj.pushKV("immature_balance", ValueFromAmount(bal.m_mine_immature));
103  obj.pushKV("txcount", (int)pwallet->mapWallet.size());
104  const auto kp_oldest = pwallet->GetOldestKeyPoolTime();
105  if (kp_oldest.has_value()) {
106  obj.pushKV("keypoololdest", kp_oldest.value());
107  }
108  obj.pushKV("keypoolsize", (int64_t)kpExternalSize);
109 
110  LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
111  if (spk_man) {
112  CKeyID seed_id = spk_man->GetHDChain().seed_id;
113  if (!seed_id.IsNull()) {
114  obj.pushKV("hdseedid", seed_id.GetHex());
115  }
116  }
117 
118  if (pwallet->CanSupportFeature(FEATURE_HD_SPLIT)) {
119  obj.pushKV("keypoolsize_hd_internal", (int64_t)(pwallet->GetKeyPoolSize() - kpExternalSize));
120  }
121  if (pwallet->IsCrypted()) {
122  obj.pushKV("unlocked_until", pwallet->nRelockTime);
123  }
124  obj.pushKV("paytxfee", ValueFromAmount(pwallet->m_pay_tx_fee.GetFeePerK()));
125  obj.pushKV("private_keys_enabled", !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
126  obj.pushKV("avoid_reuse", pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE));
127  if (pwallet->IsScanning()) {
128  UniValue scanning(UniValue::VOBJ);
129  scanning.pushKV("duration", Ticks<std::chrono::seconds>(pwallet->ScanningDuration()));
130  scanning.pushKV("progress", pwallet->ScanningProgress());
131  obj.pushKV("scanning", std::move(scanning));
132  } else {
133  obj.pushKV("scanning", false);
134  }
135  obj.pushKV("descriptors", pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
136  obj.pushKV("external_signer", pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER));
137  obj.pushKV("blank", pwallet->IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET));
138  if (int64_t birthtime = pwallet->GetBirthTime(); birthtime != UNKNOWN_TIME) {
139  obj.pushKV("birthtime", birthtime);
140  }
141 
142  AppendLastProcessedBlock(obj, *pwallet);
143  return obj;
144 },
145  };
146 }
147 
149 {
150  return RPCHelpMan{"listwalletdir",
151  "Returns a list of wallets in the wallet directory.\n",
152  {},
153  RPCResult{
154  RPCResult::Type::OBJ, "", "",
155  {
156  {RPCResult::Type::ARR, "wallets", "",
157  {
158  {RPCResult::Type::OBJ, "", "",
159  {
160  {RPCResult::Type::STR, "name", "The wallet name"},
161  }},
162  }},
163  }
164  },
165  RPCExamples{
166  HelpExampleCli("listwalletdir", "")
167  + HelpExampleRpc("listwalletdir", "")
168  },
169  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
170 {
171  UniValue wallets(UniValue::VARR);
172  for (const auto& [path, _] : ListDatabases(GetWalletDir())) {
174  wallet.pushKV("name", path.utf8string());
175  wallets.push_back(std::move(wallet));
176  }
177 
179  result.pushKV("wallets", std::move(wallets));
180  return result;
181 },
182  };
183 }
184 
186 {
187  return RPCHelpMan{"listwallets",
188  "Returns a list of currently loaded wallets.\n"
189  "For full information on the wallet, use \"getwalletinfo\"\n",
190  {},
191  RPCResult{
192  RPCResult::Type::ARR, "", "",
193  {
194  {RPCResult::Type::STR, "walletname", "the wallet name"},
195  }
196  },
197  RPCExamples{
198  HelpExampleCli("listwallets", "")
199  + HelpExampleRpc("listwallets", "")
200  },
201  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
202 {
204 
205  WalletContext& context = EnsureWalletContext(request.context);
206  for (const std::shared_ptr<CWallet>& wallet : GetWallets(context)) {
207  LOCK(wallet->cs_wallet);
208  obj.push_back(wallet->GetName());
209  }
210 
211  return obj;
212 },
213  };
214 }
215 
217 {
218  return RPCHelpMan{"loadwallet",
219  "\nLoads 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  },
236  RPCExamples{
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 RPCHelpMan& 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 : WALLET_FLAG_MAP)
284  if (it.second & MUTABLE_WALLET_FLAGS)
285  flags += (flags == "" ? "" : ", ") + it.first;
286 
287  return RPCHelpMan{"setwalletflag",
288  "\nChange the state of the given wallet flag for a wallet.\n",
289  {
290  {"flag", RPCArg::Type::STR, RPCArg::Optional::NO, "The name of the flag to change. Current available flags: " + flags},
291  {"value", RPCArg::Type::BOOL, RPCArg::Default{true}, "The new state."},
292  },
293  RPCResult{
294  RPCResult::Type::OBJ, "", "",
295  {
296  {RPCResult::Type::STR, "flag_name", "The name of the flag that was modified"},
297  {RPCResult::Type::BOOL, "flag_state", "The new state of the flag"},
298  {RPCResult::Type::STR, "warnings", /*optional=*/true, "Any warnings associated with the change"},
299  }
300  },
301  RPCExamples{
302  HelpExampleCli("setwalletflag", "avoid_reuse")
303  + HelpExampleRpc("setwalletflag", "\"avoid_reuse\"")
304  },
305  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
306 {
307  std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
308  if (!pwallet) return UniValue::VNULL;
309 
310  std::string flag_str = request.params[0].get_str();
311  bool value = request.params[1].isNull() || request.params[1].get_bool();
312 
313  if (!WALLET_FLAG_MAP.count(flag_str)) {
314  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Unknown wallet flag: %s", flag_str));
315  }
316 
317  auto flag = WALLET_FLAG_MAP.at(flag_str);
318 
319  if (!(flag & MUTABLE_WALLET_FLAGS)) {
320  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is immutable: %s", flag_str));
321  }
322 
324 
325  if (pwallet->IsWalletFlagSet(flag) == value) {
326  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is already set to %s: %s", value ? "true" : "false", flag_str));
327  }
328 
329  res.pushKV("flag_name", flag_str);
330  res.pushKV("flag_state", value);
331 
332  if (value) {
333  pwallet->SetWalletFlag(flag);
334  } else {
335  pwallet->UnsetWalletFlag(flag);
336  }
337 
338  if (flag && value && WALLET_FLAG_CAVEATS.count(flag)) {
339  res.pushKV("warnings", WALLET_FLAG_CAVEATS.at(flag));
340  }
341 
342  return res;
343 },
344  };
345 }
346 
348 {
349  return RPCHelpMan{
350  "createwallet",
351  "\nCreates and loads a new wallet.\n",
352  {
353  {"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."},
354  {"disable_private_keys", RPCArg::Type::BOOL, RPCArg::Default{false}, "Disable the possibility of private keys (only watchonlys are possible in this mode)."},
355  {"blank", RPCArg::Type::BOOL, RPCArg::Default{false}, "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."},
356  {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."},
357  {"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."},
358  {"descriptors", RPCArg::Type::BOOL, RPCArg::Default{true}, "Create a native descriptor wallet. The wallet will use descriptors internally to handle address creation."
359  " Setting to \"false\" will create a legacy wallet; This is only possible with the -deprecatedrpc=create_bdb setting because, the legacy wallet type is being deprecated and"
360  " support for creating and opening legacy wallets will be removed in the future."},
361  {"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."},
362  {"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."},
363  },
364  RPCResult{
365  RPCResult::Type::OBJ, "", "",
366  {
367  {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."},
368  {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to creating and loading the wallet.",
369  {
370  {RPCResult::Type::STR, "", ""},
371  }},
372  }
373  },
374  RPCExamples{
375  HelpExampleCli("createwallet", "\"testwallet\"")
376  + HelpExampleRpc("createwallet", "\"testwallet\"")
377  + HelpExampleCliNamed("createwallet", {{"wallet_name", "descriptors"}, {"avoid_reuse", true}, {"descriptors", true}, {"load_on_startup", true}})
378  + HelpExampleRpcNamed("createwallet", {{"wallet_name", "descriptors"}, {"avoid_reuse", true}, {"descriptors", true}, {"load_on_startup", true}})
379  },
380  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
381 {
382  WalletContext& context = EnsureWalletContext(request.context);
383  uint64_t flags = 0;
384  if (!request.params[1].isNull() && request.params[1].get_bool()) {
386  }
387 
388  if (!request.params[2].isNull() && request.params[2].get_bool()) {
390  }
391  SecureString passphrase;
392  passphrase.reserve(100);
393  std::vector<bilingual_str> warnings;
394  if (!request.params[3].isNull()) {
395  passphrase = std::string_view{request.params[3].get_str()};
396  if (passphrase.empty()) {
397  // Empty string means unencrypted
398  warnings.emplace_back(Untranslated("Empty string given as passphrase, wallet will not be encrypted."));
399  }
400  }
401 
402  if (!request.params[4].isNull() && request.params[4].get_bool()) {
404  }
405  if (self.Arg<bool>("descriptors")) {
406 #ifndef USE_SQLITE
407  throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without sqlite support (required for descriptor wallets)");
408 #endif
410  } else {
411  if (!context.chain->rpcEnableDeprecated("create_bdb")) {
412  throw JSONRPCError(RPC_WALLET_ERROR, "BDB wallet creation is deprecated and will be removed in a future release."
413  " In this release it can be re-enabled temporarily with the -deprecatedrpc=create_bdb setting.");
414  }
415  }
416  if (!request.params[7].isNull() && request.params[7].get_bool()) {
417 #ifdef ENABLE_EXTERNAL_SIGNER
419 #else
420  throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without external signing support (required for external signing)");
421 #endif
422  }
423 
424 #ifndef USE_BDB
425  if (!(flags & WALLET_FLAG_DESCRIPTORS)) {
426  throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without bdb support (required for legacy wallets)");
427  }
428 #endif
429 
430  DatabaseOptions options;
431  DatabaseStatus status;
432  ReadDatabaseArgs(*context.args, options);
433  options.require_create = true;
434  options.create_flags = flags;
435  options.create_passphrase = passphrase;
436  bilingual_str error;
437  std::optional<bool> load_on_start = request.params[6].isNull() ? std::nullopt : std::optional<bool>(request.params[6].get_bool());
438  const std::shared_ptr<CWallet> wallet = CreateWallet(context, request.params[0].get_str(), load_on_start, options, status, error, warnings);
439  if (!wallet) {
440  RPCErrorCode code = status == DatabaseStatus::FAILED_ENCRYPT ? RPC_WALLET_ENCRYPTION_FAILED : RPC_WALLET_ERROR;
441  throw JSONRPCError(code, error.original);
442  }
443 
445  obj.pushKV("name", wallet->GetName());
446  PushWarnings(warnings, obj);
447 
448  return obj;
449 },
450  };
451 }
452 
454 {
455  return RPCHelpMan{"unloadwallet",
456  "Unloads the wallet referenced by the request endpoint, otherwise unloads the wallet specified in the argument.\n"
457  "Specifying the wallet name on a wallet endpoint is invalid.",
458  {
459  {"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."},
460  {"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."},
461  },
463  {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to unloading the wallet.",
464  {
465  {RPCResult::Type::STR, "", ""},
466  }},
467  }},
468  RPCExamples{
469  HelpExampleCli("unloadwallet", "wallet_name")
470  + HelpExampleRpc("unloadwallet", "wallet_name")
471  },
472  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
473 {
474  std::string wallet_name;
475  if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
476  if (!(request.params[0].isNull() || request.params[0].get_str() == wallet_name)) {
477  throw JSONRPCError(RPC_INVALID_PARAMETER, "RPC endpoint wallet and wallet_name parameter specify different wallets");
478  }
479  } else {
480  wallet_name = request.params[0].get_str();
481  }
482 
483  WalletContext& context = EnsureWalletContext(request.context);
484  std::shared_ptr<CWallet> wallet = GetWallet(context, wallet_name);
485  if (!wallet) {
486  throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
487  }
488 
489  std::vector<bilingual_str> warnings;
490  {
491  WalletRescanReserver reserver(*wallet);
492  if (!reserver.reserve()) {
493  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
494  }
495 
496  // Release the "main" shared pointer and prevent further notifications.
497  // Note that any attempt to load the same wallet would fail until the wallet
498  // is destroyed (see CheckUniqueFileid).
499  std::optional<bool> load_on_start{self.MaybeArg<bool>("load_on_startup")};
500  if (!RemoveWallet(context, wallet, load_on_start, warnings)) {
501  throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded");
502  }
503  }
504 
505  WaitForDeleteWallet(std::move(wallet));
506 
508  PushWarnings(warnings, result);
509 
510  return result;
511 },
512  };
513 }
514 
516 {
517  return RPCHelpMan{"sethdseed",
518  "\nSet or generate a new HD wallet seed. Non-HD wallets will not be upgraded to being a HD wallet. Wallets that are already\n"
519  "HD will have a new HD seed set so that new keys added to the keypool will be derived from this new seed.\n"
520  "\nNote that you will need to MAKE A NEW BACKUP of your wallet after setting the HD wallet seed." + HELP_REQUIRING_PASSPHRASE +
521  "Note: This command is only compatible with legacy wallets.\n",
522  {
523  {"newkeypool", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether to flush old unused addresses, including change addresses, from the keypool and regenerate it.\n"
524  "If true, the next address from getnewaddress and change address from getrawchangeaddress will be from this new seed.\n"
525  "If false, addresses (including change addresses if the wallet already had HD Chain Split enabled) from the existing\n"
526  "keypool will be used until it has been depleted."},
527  {"seed", RPCArg::Type::STR, RPCArg::DefaultHint{"random seed"}, "The WIF private key to use as the new HD seed.\n"
528  "The seed value can be retrieved using the dumpwallet command. It is the private key marked hdseed=1"},
529  },
531  RPCExamples{
532  HelpExampleCli("sethdseed", "")
533  + HelpExampleCli("sethdseed", "false")
534  + HelpExampleCli("sethdseed", "true \"wifkey\"")
535  + HelpExampleRpc("sethdseed", "true, \"wifkey\"")
536  },
537  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
538 {
539  std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
540  if (!pwallet) return UniValue::VNULL;
541 
542  LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet, true);
543 
544  if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
545  throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed to a wallet with private keys disabled");
546  }
547 
548  LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
549 
550  // Do not do anything to non-HD wallets
551  if (!pwallet->CanSupportFeature(FEATURE_HD)) {
552  throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set an HD seed on a non-HD wallet. Use the upgradewallet RPC in order to upgrade a non-HD wallet to HD");
553  }
554 
555  EnsureWalletIsUnlocked(*pwallet);
556 
557  bool flush_key_pool = true;
558  if (!request.params[0].isNull()) {
559  flush_key_pool = request.params[0].get_bool();
560  }
561 
562  CPubKey master_pub_key;
563  if (request.params[1].isNull()) {
564  master_pub_key = spk_man.GenerateNewSeed();
565  } else {
566  CKey key = DecodeSecret(request.params[1].get_str());
567  if (!key.IsValid()) {
568  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
569  }
570 
571  if (HaveKey(spk_man, key)) {
572  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Already have this key (either as an HD seed or as a loose private key)");
573  }
574 
575  master_pub_key = spk_man.DeriveNewSeed(key);
576  }
577 
578  spk_man.SetHDSeed(master_pub_key);
579  if (flush_key_pool) spk_man.NewKeyPool();
580 
581  return UniValue::VNULL;
582 },
583  };
584 }
585 
587 {
588  return RPCHelpMan{"upgradewallet",
589  "\nUpgrade the wallet. Upgrades to the latest version if no version number is specified.\n"
590  "New keys may be generated and a new wallet backup will need to be made.",
591  {
592  {"version", RPCArg::Type::NUM, RPCArg::Default{int{FEATURE_LATEST}}, "The version number to upgrade to. Default is the latest wallet version."}
593  },
594  RPCResult{
595  RPCResult::Type::OBJ, "", "",
596  {
597  {RPCResult::Type::STR, "wallet_name", "Name of wallet this operation was performed on"},
598  {RPCResult::Type::NUM, "previous_version", "Version of wallet before this operation"},
599  {RPCResult::Type::NUM, "current_version", "Version of wallet after this operation"},
600  {RPCResult::Type::STR, "result", /*optional=*/true, "Description of result, if no error"},
601  {RPCResult::Type::STR, "error", /*optional=*/true, "Error message (if there is one)"}
602  },
603  },
604  RPCExamples{
605  HelpExampleCli("upgradewallet", "169900")
606  + HelpExampleRpc("upgradewallet", "169900")
607  },
608  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
609 {
610  std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
611  if (!pwallet) return UniValue::VNULL;
612 
613  EnsureWalletIsUnlocked(*pwallet);
614 
615  int version = 0;
616  if (!request.params[0].isNull()) {
617  version = request.params[0].getInt<int>();
618  }
619  bilingual_str error;
620  const int previous_version{pwallet->GetVersion()};
621  const bool wallet_upgraded{pwallet->UpgradeWallet(version, error)};
622  const int current_version{pwallet->GetVersion()};
623  std::string result;
624 
625  if (wallet_upgraded) {
626  if (previous_version == current_version) {
627  result = "Already at latest version. Wallet version unchanged.";
628  } else {
629  result = strprintf("Wallet upgraded successfully from version %i to version %i.", previous_version, current_version);
630  }
631  }
632 
634  obj.pushKV("wallet_name", pwallet->GetName());
635  obj.pushKV("previous_version", previous_version);
636  obj.pushKV("current_version", current_version);
637  if (!result.empty()) {
638  obj.pushKV("result", result);
639  } else {
640  CHECK_NONFATAL(!error.empty());
641  obj.pushKV("error", error.original);
642  }
643  return obj;
644 },
645  };
646 }
647 
649 {
650  return RPCHelpMan{"simulaterawtransaction",
651  "\nCalculate the balance change resulting in the signing and broadcasting of the given transaction(s).\n",
652  {
653  {"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "An array of hex strings of raw transactions.\n",
654  {
656  },
657  },
659  {
660  {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses (see RPC importaddress)"},
661  },
662  },
663  },
664  RPCResult{
665  RPCResult::Type::OBJ, "", "",
666  {
667  {RPCResult::Type::STR_AMOUNT, "balance_change", "The wallet balance change (negative means decrease)."},
668  }
669  },
670  RPCExamples{
671  HelpExampleCli("simulaterawtransaction", "[\"myhex\"]")
672  + HelpExampleRpc("simulaterawtransaction", "[\"myhex\"]")
673  },
674  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
675 {
676  const std::shared_ptr<const CWallet> rpc_wallet = GetWalletForJSONRPCRequest(request);
677  if (!rpc_wallet) return UniValue::VNULL;
678  const CWallet& wallet = *rpc_wallet;
679 
680  LOCK(wallet.cs_wallet);
681 
682  UniValue include_watchonly(UniValue::VNULL);
683  if (request.params[1].isObject()) {
684  UniValue options = request.params[1];
685  RPCTypeCheckObj(options,
686  {
687  {"include_watchonly", UniValueType(UniValue::VBOOL)},
688  },
689  true, true);
690 
691  include_watchonly = options["include_watchonly"];
692  }
693 
695  if (ParseIncludeWatchonly(include_watchonly, wallet)) {
696  filter |= ISMINE_WATCH_ONLY;
697  }
698 
699  const auto& txs = request.params[0].get_array();
700  CAmount changes{0};
701  std::map<COutPoint, CAmount> new_utxos; // UTXO:s that were made available in transaction array
702  std::set<COutPoint> spent;
703 
704  for (size_t i = 0; i < txs.size(); ++i) {
706  if (!DecodeHexTx(mtx, txs[i].get_str(), /* try_no_witness */ true, /* try_witness */ true)) {
707  throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Transaction hex string decoding failure.");
708  }
709 
710  // Fetch previous transactions (inputs)
711  std::map<COutPoint, Coin> coins;
712  for (const CTxIn& txin : mtx.vin) {
713  coins[txin.prevout]; // Create empty map entry keyed by prevout.
714  }
715  wallet.chain().findCoins(coins);
716 
717  // Fetch debit; we are *spending* these; if the transaction is signed and
718  // broadcast, we will lose everything in these
719  for (const auto& txin : mtx.vin) {
720  const auto& outpoint = txin.prevout;
721  if (spent.count(outpoint)) {
722  throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction(s) are spending the same output more than once");
723  }
724  if (new_utxos.count(outpoint)) {
725  changes -= new_utxos.at(outpoint);
726  new_utxos.erase(outpoint);
727  } else {
728  if (coins.at(outpoint).IsSpent()) {
729  throw JSONRPCError(RPC_INVALID_PARAMETER, "One or more transaction inputs are missing or have been spent already");
730  }
731  changes -= wallet.GetDebit(txin, filter);
732  }
733  spent.insert(outpoint);
734  }
735 
736  // Iterate over outputs; we are *receiving* these, if the wallet considers
737  // them "mine"; if the transaction is signed and broadcast, we will receive
738  // everything in these
739  // Also populate new_utxos in case these are spent in later transactions
740 
741  const auto& hash = mtx.GetHash();
742  for (size_t i = 0; i < mtx.vout.size(); ++i) {
743  const auto& txout = mtx.vout[i];
744  bool is_mine = 0 < (wallet.IsMine(txout) & filter);
745  changes += new_utxos[COutPoint(hash, i)] = is_mine ? txout.nValue : 0;
746  }
747  }
748 
750  result.pushKV("balance_change", ValueFromAmount(changes));
751 
752  return result;
753 }
754  };
755 }
756 
758 {
759  return RPCHelpMan{"migratewallet",
760  "\nMigrate the wallet to a descriptor wallet.\n"
761  "A new wallet backup will need to be made.\n"
762  "\nThe migration process will create a backup of the wallet before migrating. This backup\n"
763  "file will be named <wallet name>-<timestamp>.legacy.bak and can be found in the directory\n"
764  "for this wallet. In the event of an incorrect migration, the backup can be restored using restorewallet."
765  "\nEncrypted wallets must have the passphrase provided as an argument to this call.\n"
766  "\nThis RPC may take a long time to complete. Increasing the RPC client timeout is recommended.",
767  {
768  {"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."},
769  {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "The wallet passphrase"},
770  },
771  RPCResult{
772  RPCResult::Type::OBJ, "", "",
773  {
774  {RPCResult::Type::STR, "wallet_name", "The name of the primary migrated wallet"},
775  {RPCResult::Type::STR, "watchonly_name", /*optional=*/true, "The name of the migrated wallet containing the watchonly scripts"},
776  {RPCResult::Type::STR, "solvables_name", /*optional=*/true, "The name of the migrated wallet containing solvable but not watched scripts"},
777  {RPCResult::Type::STR, "backup_path", "The location of the backup of the original wallet"},
778  }
779  },
780  RPCExamples{
781  HelpExampleCli("migratewallet", "")
782  + HelpExampleRpc("migratewallet", "")
783  },
784  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
785  {
786  std::string wallet_name;
787  if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
788  if (!(request.params[0].isNull() || request.params[0].get_str() == wallet_name)) {
789  throw JSONRPCError(RPC_INVALID_PARAMETER, "RPC endpoint wallet and wallet_name parameter specify different wallets");
790  }
791  } else {
792  if (request.params[0].isNull()) {
793  throw JSONRPCError(RPC_INVALID_PARAMETER, "Either RPC endpoint wallet or wallet_name parameter must be provided");
794  }
795  wallet_name = request.params[0].get_str();
796  }
797 
798  SecureString wallet_pass;
799  wallet_pass.reserve(100);
800  if (!request.params[1].isNull()) {
801  wallet_pass = std::string_view{request.params[1].get_str()};
802  }
803 
804  WalletContext& context = EnsureWalletContext(request.context);
805  util::Result<MigrationResult> res = MigrateLegacyToDescriptor(wallet_name, wallet_pass, context);
806  if (!res) {
807  throw JSONRPCError(RPC_WALLET_ERROR, util::ErrorString(res).original);
808  }
809 
811  r.pushKV("wallet_name", res->wallet_name);
812  if (res->watchonly_wallet) {
813  r.pushKV("watchonly_name", res->watchonly_wallet->GetName());
814  }
815  if (res->solvables_wallet) {
816  r.pushKV("solvables_name", res->solvables_wallet->GetName());
817  }
818  r.pushKV("backup_path", res->backup_path.utf8string());
819 
820  return r;
821  },
822  };
823 }
824 
826 {
827  return RPCHelpMan{
828  "gethdkeys",
829  "\nList all BIP 32 HD keys in the wallet and which descriptors use them.\n",
830  {
832  {"active_only", RPCArg::Type::BOOL, RPCArg::Default{false}, "Show the keys for only active descriptors"},
833  {"private", RPCArg::Type::BOOL, RPCArg::Default{false}, "Show private keys"}
834  }},
835  },
837  {
838  {RPCResult::Type::OBJ, "", "", {
839  {RPCResult::Type::STR, "xpub", "The extended public key"},
840  {RPCResult::Type::BOOL, "has_private", "Whether the wallet has the private key for this xpub"},
841  {RPCResult::Type::STR, "xprv", /*optional=*/true, "The extended private key if \"private\" is true"},
842  {RPCResult::Type::ARR, "descriptors", "Array of descriptor objects that use this HD key",
843  {
844  {RPCResult::Type::OBJ, "", "", {
845  {RPCResult::Type::STR, "desc", "Descriptor string representation"},
846  {RPCResult::Type::BOOL, "active", "Whether this descriptor is currently used to generate new addresses"},
847  }},
848  }},
849  }},
850  }
851  }},
852  RPCExamples{
853  HelpExampleCli("gethdkeys", "") + HelpExampleRpc("gethdkeys", "")
854  + HelpExampleCliNamed("gethdkeys", {{"active_only", "true"}, {"private", "true"}}) + HelpExampleRpcNamed("gethdkeys", {{"active_only", "true"}, {"private", "true"}})
855  },
856  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
857  {
858  const std::shared_ptr<const CWallet> wallet = GetWalletForJSONRPCRequest(request);
859  if (!wallet) return UniValue::VNULL;
860 
861  if (!wallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
862  throw JSONRPCError(RPC_WALLET_ERROR, "gethdkeys is not available for non-descriptor wallets");
863  }
864 
865  LOCK(wallet->cs_wallet);
866 
867  UniValue options{request.params[0].isNull() ? UniValue::VOBJ : request.params[0]};
868  const bool active_only{options.exists("active_only") ? options["active_only"].get_bool() : false};
869  const bool priv{options.exists("private") ? options["private"].get_bool() : false};
870  if (priv) {
872  }
873 
874 
875  std::set<ScriptPubKeyMan*> spkms;
876  if (active_only) {
877  spkms = wallet->GetActiveScriptPubKeyMans();
878  } else {
879  spkms = wallet->GetAllScriptPubKeyMans();
880  }
881 
882  std::map<CExtPubKey, std::set<std::tuple<std::string, bool, bool>>> wallet_xpubs;
883  std::map<CExtPubKey, CExtKey> wallet_xprvs;
884  for (auto* spkm : spkms) {
885  auto* desc_spkm{dynamic_cast<DescriptorScriptPubKeyMan*>(spkm)};
886  CHECK_NONFATAL(desc_spkm);
887  LOCK(desc_spkm->cs_desc_man);
888  WalletDescriptor w_desc = desc_spkm->GetWalletDescriptor();
889 
890  // Retrieve the pubkeys from the descriptor
891  std::set<CPubKey> desc_pubkeys;
892  std::set<CExtPubKey> desc_xpubs;
893  w_desc.descriptor->GetPubKeys(desc_pubkeys, desc_xpubs);
894  for (const CExtPubKey& xpub : desc_xpubs) {
895  std::string desc_str;
896  bool ok = desc_spkm->GetDescriptorString(desc_str, false);
897  CHECK_NONFATAL(ok);
898  wallet_xpubs[xpub].emplace(desc_str, wallet->IsActiveScriptPubKeyMan(*spkm), desc_spkm->HasPrivKey(xpub.pubkey.GetID()));
899  if (std::optional<CKey> key = priv ? desc_spkm->GetKey(xpub.pubkey.GetID()) : std::nullopt) {
900  wallet_xprvs[xpub] = CExtKey(xpub, *key);
901  }
902  }
903  }
904 
905  UniValue response(UniValue::VARR);
906  for (const auto& [xpub, descs] : wallet_xpubs) {
907  bool has_xprv = false;
908  UniValue descriptors(UniValue::VARR);
909  for (const auto& [desc, active, has_priv] : descs) {
911  d.pushKV("desc", desc);
912  d.pushKV("active", active);
913  has_xprv |= has_priv;
914 
915  descriptors.push_back(std::move(d));
916  }
917  UniValue xpub_info(UniValue::VOBJ);
918  xpub_info.pushKV("xpub", EncodeExtPubKey(xpub));
919  xpub_info.pushKV("has_private", has_xprv);
920  if (priv) {
921  xpub_info.pushKV("xprv", EncodeExtKey(wallet_xprvs.at(xpub)));
922  }
923  xpub_info.pushKV("descriptors", std::move(descriptors));
924 
925  response.push_back(std::move(xpub_info));
926  }
927 
928  return response;
929  },
930  };
931 }
932 
934 {
935  return RPCHelpMan{"createwalletdescriptor",
936  "Creates the wallet's descriptor for the given address type. "
937  "The address type must be one that the wallet does not already have a descriptor for."
939  {
940  {"type", RPCArg::Type::STR, RPCArg::Optional::NO, "The address type the descriptor will produce. Options are \"legacy\", \"p2sh-segwit\", \"bech32\", and \"bech32m\"."},
942  {"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)"},
943  {"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"},
944  }},
945  },
946  RPCResult{
947  RPCResult::Type::OBJ, "", "",
948  {
949  {RPCResult::Type::ARR, "descs", "The public descriptors that were added to the wallet",
950  {{RPCResult::Type::STR, "", ""}}
951  }
952  },
953  },
954  RPCExamples{
955  HelpExampleCli("createwalletdescriptor", "bech32m")
956  + HelpExampleRpc("createwalletdescriptor", "bech32m")
957  },
958  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
959  {
960  std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
961  if (!pwallet) return UniValue::VNULL;
962 
963  // Make sure wallet is a descriptor wallet
964  if (!pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
965  throw JSONRPCError(RPC_WALLET_ERROR, "createwalletdescriptor is not available for non-descriptor wallets");
966  }
967 
968  std::optional<OutputType> output_type = ParseOutputType(request.params[0].get_str());
969  if (!output_type) {
970  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[0].get_str()));
971  }
972 
973  UniValue options{request.params[1].isNull() ? UniValue::VOBJ : request.params[1]};
974  UniValue internal_only{options["internal"]};
975  UniValue hdkey{options["hdkey"]};
976 
977  std::vector<bool> internals;
978  if (internal_only.isNull()) {
979  internals.push_back(false);
980  internals.push_back(true);
981  } else {
982  internals.push_back(internal_only.get_bool());
983  }
984 
985  LOCK(pwallet->cs_wallet);
986  EnsureWalletIsUnlocked(*pwallet);
987 
988  CExtPubKey xpub;
989  if (hdkey.isNull()) {
990  std::set<CExtPubKey> active_xpubs = pwallet->GetActiveHDPubKeys();
991  if (active_xpubs.size() != 1) {
992  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to determine which HD key to use from active descriptors. Please specify with 'hdkey'");
993  }
994  xpub = *active_xpubs.begin();
995  } else {
996  xpub = DecodeExtPubKey(hdkey.get_str());
997  if (!xpub.pubkey.IsValid()) {
998  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to parse HD key. Please provide a valid xpub");
999  }
1000  }
1001 
1002  std::optional<CKey> key = pwallet->GetKey(xpub.pubkey.GetID());
1003  if (!key) {
1004  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Private key for %s is not known", EncodeExtPubKey(xpub)));
1005  }
1006  CExtKey active_hdkey(xpub, *key);
1007 
1008  std::vector<std::reference_wrapper<DescriptorScriptPubKeyMan>> spkms;
1009  WalletBatch batch{pwallet->GetDatabase()};
1010  for (bool internal : internals) {
1011  WalletDescriptor w_desc = GenerateWalletDescriptor(xpub, *output_type, internal);
1012  uint256 w_id = DescriptorID(*w_desc.descriptor);
1013  if (!pwallet->GetScriptPubKeyMan(w_id)) {
1014  spkms.emplace_back(pwallet->SetupDescriptorScriptPubKeyMan(batch, active_hdkey, *output_type, internal));
1015  }
1016  }
1017  if (spkms.empty()) {
1018  throw JSONRPCError(RPC_WALLET_ERROR, "Descriptor already exists");
1019  }
1020 
1021  // Fetch each descspkm from the wallet in order to get the descriptor strings
1022  UniValue descs{UniValue::VARR};
1023  for (const auto& spkm : spkms) {
1024  std::string desc_str;
1025  bool ok = spkm.get().GetDescriptorString(desc_str, false);
1026  CHECK_NONFATAL(ok);
1027  descs.push_back(desc_str);
1028  }
1030  out.pushKV("descs", std::move(descs));
1031  return out;
1032  }
1033  };
1034 }
1035 
1036 // addresses
1047 #ifdef ENABLE_EXTERNAL_SIGNER
1049 #endif // ENABLE_EXTERNAL_SIGNER
1050 
1051 // backup
1065 
1066 // coins
1075 
1076 // encryption
1081 
1082 // spend
1089 RPCHelpMan send();
1094 
1095 // signmessage
1097 
1098 // transactions
1107 
1109 {
1110  static const CRPCCommand commands[]{
1111  {"rawtransactions", &fundrawtransaction},
1112  {"wallet", &abandontransaction},
1113  {"wallet", &abortrescan},
1114  {"wallet", &addmultisigaddress},
1115  {"wallet", &backupwallet},
1116  {"wallet", &bumpfee},
1117  {"wallet", &psbtbumpfee},
1118  {"wallet", &createwallet},
1119  {"wallet", &createwalletdescriptor},
1120  {"wallet", &restorewallet},
1121  {"wallet", &dumpprivkey},
1122  {"wallet", &dumpwallet},
1123  {"wallet", &encryptwallet},
1124  {"wallet", &getaddressesbylabel},
1125  {"wallet", &getaddressinfo},
1126  {"wallet", &getbalance},
1127  {"wallet", &gethdkeys},
1128  {"wallet", &getnewaddress},
1129  {"wallet", &getrawchangeaddress},
1130  {"wallet", &getreceivedbyaddress},
1131  {"wallet", &getreceivedbylabel},
1132  {"wallet", &gettransaction},
1133  {"wallet", &getunconfirmedbalance},
1134  {"wallet", &getbalances},
1135  {"wallet", &getwalletinfo},
1136  {"wallet", &importaddress},
1137  {"wallet", &importdescriptors},
1138  {"wallet", &importmulti},
1139  {"wallet", &importprivkey},
1140  {"wallet", &importprunedfunds},
1141  {"wallet", &importpubkey},
1142  {"wallet", &importwallet},
1143  {"wallet", &keypoolrefill},
1144  {"wallet", &listaddressgroupings},
1145  {"wallet", &listdescriptors},
1146  {"wallet", &listlabels},
1147  {"wallet", &listlockunspent},
1148  {"wallet", &listreceivedbyaddress},
1149  {"wallet", &listreceivedbylabel},
1150  {"wallet", &listsinceblock},
1151  {"wallet", &listtransactions},
1152  {"wallet", &listunspent},
1153  {"wallet", &listwalletdir},
1154  {"wallet", &listwallets},
1155  {"wallet", &loadwallet},
1156  {"wallet", &lockunspent},
1157  {"wallet", &migratewallet},
1158  {"wallet", &newkeypool},
1159  {"wallet", &removeprunedfunds},
1160  {"wallet", &rescanblockchain},
1161  {"wallet", &send},
1162  {"wallet", &sendmany},
1163  {"wallet", &sendtoaddress},
1164  {"wallet", &sethdseed},
1165  {"wallet", &setlabel},
1166  {"wallet", &settxfee},
1167  {"wallet", &setwalletflag},
1168  {"wallet", &signmessage},
1169  {"wallet", &signrawtransactionwithwallet},
1170  {"wallet", &simulaterawtransaction},
1171  {"wallet", &sendall},
1172  {"wallet", &unloadwallet},
1173  {"wallet", &upgradewallet},
1174  {"wallet", &walletcreatefundedpsbt},
1175 #ifdef ENABLE_EXTERNAL_SIGNER
1176  {"wallet", &walletdisplayaddress},
1177 #endif // ENABLE_EXTERNAL_SIGNER
1178  {"wallet", &walletlock},
1179  {"wallet", &walletpassphrase},
1180  {"wallet", &walletpassphrasechange},
1181  {"wallet", &walletprocesspsbt},
1182  };
1183  return commands;
1184 }
1185 } // namespace wallet
RPCHelpMan walletlock()
Definition: encrypt.cpp:174
RPCHelpMan importaddress()
Definition: backup.cpp:219
RPCHelpMan importwallet()
Definition: backup.cpp:488
void push_back(UniValue val)
Definition: univalue.cpp:104
void ReadDatabaseArgs(const ArgsManager &args, DatabaseOptions &options)
Definition: db.cpp:154
RPCHelpMan listlockunspent()
Definition: coins.cpp:374
static RPCHelpMan listwalletdir()
Definition: wallet.cpp:148
RPCHelpMan simulaterawtransaction()
Definition: wallet.cpp:648
static RPCHelpMan setwalletflag()
Definition: wallet.cpp:280
std::string HelpExampleRpcNamed(const std::string &methodname, const RPCArgList &args)
Definition: util.cpp:210
RPCHelpMan importmulti()
Definition: backup.cpp:1254
RPCHelpMan sendmany()
Definition: spend.cpp:324
void RPCTypeCheckObj(const UniValue &o, const std::map< std::string, UniValueType > &typesExpected, bool fAllowNull, bool fStrict)
Definition: util.cpp:59
Required arg.
RPCHelpMan restorewallet()
Definition: backup.cpp:1927
std::vector< std::pair< fs::path, std::string > > ListDatabases(const fs::path &wallet_dir)
Recursively list database paths in directory.
Definition: db.cpp:23
Bilingual messages:
Definition: translation.h:24
bool NewKeyPool()
Mark old keypool keys as used, and generate all new keys.
static RPCHelpMan loadwallet()
Definition: wallet.cpp:216
bool empty() const
Definition: translation.h:35
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
RecursiveMutex cs_KeyStore
RPCHelpMan walletpassphrase()
Definition: encrypt.cpp:11
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:182
RPCHelpMan sendtoaddress()
Definition: spend.cpp:227
RPCHelpMan gethdkeys()
Definition: wallet.cpp:825
std::vector< CTxIn > vin
Definition: transaction.h:379
RPCHelpMan getreceivedbylabel()
Definition: coins.cpp:122
WalletDescriptor GenerateWalletDescriptor(const CExtPubKey &master_key, const OutputType &addr_type, bool internal)
Definition: walletutil.cpp:49
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:82
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:370
Definition: key.h:227
RPCHelpMan listtransactions()
RPCHelpMan abandontransaction()
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:81
RPCHelpMan psbtbumpfee()
Definition: spend.cpp:1197
Special type that behaves almost exactly like OBJ, defining an options object with a list of pre-defi...
RPCHelpMan lockunspent()
Definition: coins.cpp:238
static RPCHelpMan sethdseed()
Definition: wallet.cpp:515
std::basic_string< char, std::char_traits< char >, secure_allocator< char > > SecureString
Definition: secure.h:58
bool ParseIncludeWatchonly(const UniValue &include_watchonly, const CWallet &wallet)
Used by RPC commands that have an include_watchonly parameter.
Definition: util.cpp:36
void SetHDSeed(const CPubKey &key)
const std::byte * end() const
Definition: key.h:120
RAII object to check and reserve a wallet rescan.
Definition: wallet.h:1081
Balance GetBalance(const CWallet &wallet, const int min_depth, bool avoid_reuse)
Definition: receive.cpp:293
static const RPCResult RESULT_LAST_PROCESSED_BLOCK
Definition: util.h:28
bool reserve(bool with_passphrase=false)
Definition: wallet.h:1092
RPCHelpMan getaddressinfo()
Definition: addresses.cpp:520
Access to the wallet database.
Definition: walletdb.h:195
RPCHelpMan send()
Definition: spend.cpp:1199
fs::path GetWalletDir()
Get the path of the wallet directory.
Definition: walletutil.cpp:13
consteval auto _(util::TranslatedLiteral str)
Definition: translation.h:79
RPCHelpMan sendall()
Definition: spend.cpp:1320
CExtPubKey DecodeExtPubKey(const std::string &str)
Definition: key_io.cpp:244
This same wallet is already loaded.
Definition: protocol.h:82
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:164
Flag set when a wallet contains no HD seed and no private keys, scripts, addresses, and other watch only things, and is therefore "blank.".
Definition: walletutil.h:71
Invalid, missing or duplicate parameter.
Definition: protocol.h:44
static constexpr uint64_t MUTABLE_WALLET_FLAGS
Definition: wallet.h:159
static RPCHelpMan getwalletinfo()
Definition: wallet.cpp:42
static RPCHelpMan unloadwallet()
Definition: wallet.cpp:453
RPCHelpMan rescanblockchain()
RPCHelpMan walletdisplayaddress()
Definition: addresses.cpp:782
RPCHelpMan signmessage()
Definition: signmessage.cpp:14
void HandleWalletError(const std::shared_ptr< CWallet > wallet, DatabaseStatus &status, bilingual_str &error)
Definition: util.cpp:139
RPCHelpMan walletcreatefundedpsbt()
Definition: spend.cpp:1663
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
Special type that is a STR with only hex chars.
RPCHelpMan walletpassphrasechange()
Definition: encrypt.cpp:115
Indicates that the wallet needs an external signer.
Definition: walletutil.h:77
#define LOCK2(cs1, cs2)
Definition: sync.h:258
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:204
RPCHelpMan fundrawtransaction()
Definition: spend.cpp:738
static constexpr int64_t UNKNOWN_TIME
Constant representing an unknown spkm creation time.
std::underlying_type< isminetype >::type isminefilter
used for bitflags of isminetype
Definition: wallet.h:48
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:70
void WaitForDeleteWallet(std::shared_ptr< CWallet > &&wallet)
Explicitly delete the wallet.
Definition: wallet.cpp:252
RPCHelpMan signrawtransactionwithwallet()
Definition: spend.cpp:875
Special string with only hex chars.
SecureString create_passphrase
Definition: db.h:196
RPCHelpMan setlabel()
Definition: addresses.cpp:120
RPCHelpMan listsinceblock()
bool RemoveWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet, std::optional< bool > load_on_start)
Definition: wallet.cpp:185
RPCHelpMan walletprocesspsbt()
Definition: spend.cpp:1580
uint64_t create_flags
Definition: db.h:195
An input of a transaction.
Definition: transaction.h:66
static RPCHelpMan createwallet()
Definition: wallet.cpp:347
#define LOCK(cs)
Definition: sync.h:257
const char * name
Definition: rest.cpp:49
std::optional< OutputType > ParseOutputType(const std::string &type)
Definition: outputtype.cpp:24
bool IsValid() const
Definition: pubkey.h:189
RPCHelpMan listreceivedbylabel()
std::shared_ptr< Descriptor > descriptor
Definition: walletutil.h:87
An encapsulated public key.
Definition: pubkey.h:33
RPCHelpMan listunspent()
Definition: coins.cpp:497
RPCHelpMan newkeypool()
Definition: addresses.cpp:380
WalletContext & EnsureWalletContext(const std::any &context)
Definition: util.cpp:88
RPCHelpMan listdescriptors()
Definition: backup.cpp:1780
Indicate that this wallet supports DescriptorScriptPubKeyMan.
Definition: walletutil.h:74
const std::string CURRENCY_UNIT
Definition: feerate.h:17
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:299
General application defined errors.
Definition: protocol.h:40
std::string DefaultHint
Hint for default value.
Definition: util.h:217
std::string HelpExampleCliNamed(const std::string &methodname, const RPCArgList &args)
Definition: util.cpp:191
void PushWarnings(const UniValue &warnings, UniValue &obj)
Push warning messages to an RPC "warnings" field as a JSON array of strings.
Definition: util.cpp:1401
bool IsCompressed() const
Check whether the public key corresponding to this private key is (to be) compressed.
Definition: key.h:126
void ReadDatabaseArgs(const ArgsManager &args, DBOptions &options)
Invalid address or key.
Definition: protocol.h:42
Txid GetHash() const
Compute the hash of this CMutableTransaction.
Definition: transaction.cpp:69
Invalid wallet specified.
Definition: protocol.h:80
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:28
static const std::map< std::string, WalletFlags > WALLET_FLAG_MAP
Definition: wallet.h:162
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:186
std::vector< CTxOut > vout
Definition: transaction.h:380
constexpr bool IsNull() const
Definition: uint256.h:48
void Set(const T pbegin, const T pend, bool fCompressedIn)
Initialize using begin and end iterators to byte data.
Definition: key.h:103
RPCHelpMan dumpprivkey()
Definition: backup.cpp:636
util::Result< MigrationResult > MigrateLegacyToDescriptor(std::shared_ptr< CWallet > local_wallet, const SecureString &passphrase, WalletContext &context, bool was_loaded)
Requirement: The wallet provided to this function must be isolated, with no attachment to the node&#39;s ...
Definition: wallet.cpp:4471
const std::string HELP_REQUIRING_PASSPHRASE
Definition: util.cpp:19
bool isNull() const
Definition: univalue.h:79
Special numeric to denote unix epoch time.
RPCHelpMan listreceivedbyaddress()
RPCHelpMan importdescriptors()
Definition: backup.cpp:1615
Descriptor with some wallet metadata.
Definition: walletutil.h:84
LegacyScriptPubKeyMan & EnsureLegacyScriptPubKeyMan(CWallet &wallet, bool also_create)
Definition: util.cpp:98
RPCHelpMan encryptwallet()
Definition: encrypt.cpp:216
int flags
Definition: bitcoin-tx.cpp:536
std::shared_ptr< CWallet > GetWallet(WalletContext &context, const std::string &name)
Definition: wallet.cpp:204
RPCHelpMan importpubkey()
Definition: backup.cpp:409
Failed to encrypt the wallet.
Definition: protocol.h:78
DatabaseStatus
Definition: db.h:205
256-bit opaque blob.
Definition: uint256.h:201
Optional argument for which the default value is omitted from help text for one of two reasons: ...
CPubKey DeriveNewSeed(const CKey &key)
std::string EncodeExtPubKey(const CExtPubKey &key)
Definition: key_io.cpp:257
RPCHelpMan getunconfirmedbalance()
Definition: coins.cpp:215
std::vector< std::shared_ptr< CWallet > > GetWallets(WalletContext &context)
Definition: wallet.cpp:191
auto result
Definition: common-types.h:74
RPCHelpMan listlabels()
Definition: addresses.cpp:726
An interface to be implemented by keystores that support signing.
RPCHelpMan importprunedfunds()
Definition: backup.cpp:321
std::string original
Definition: translation.h:25
Special string to represent a floating point amount.
void pushKV(std::string key, UniValue val)
Definition: univalue.cpp:126
RPCHelpMan dumpwallet()
Definition: backup.cpp:683
RPCHelpMan gettransaction()
const std::byte * begin() const
Definition: key.h:119
RPCHelpMan getaddressesbylabel()
Definition: addresses.cpp:666
RPCHelpMan importprivkey()
Definition: backup.cpp:116
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:23
bool DecodeHexTx(CMutableTransaction &tx, const std::string &hex_tx, bool try_no_witness=false, bool try_witness=true)
Definition: core_read.cpp:196
std::string GetHex() const
Definition: uint256.cpp:11
uint256 DescriptorID(const Descriptor &desc)
Unique identifier that may not change over time, unless explicitly marked as not backwards compatible...
bool HaveKey(const SigningProvider &wallet, const CKey &key)
Checks if a CKey is in the given CWallet compressed or otherwise.
Definition: wallet.cpp:35
UniValue ValueFromAmount(const CAmount amount)
Definition: core_write.cpp:26
WalletContext struct containing references to state shared between CWallet instances, like the reference to the chain interface, and the list of opened wallets.
Definition: context.h:36
RPCHelpMan abortrescan()
void EnsureWalletIsUnlocked(const CWallet &wallet)
Definition: util.cpp:81
bilingual_str ErrorString(const Result< T > &result)
Definition: result.h:93
RPCHelpMan keypoolrefill()
Definition: addresses.cpp:336
interfaces::Chain * chain
Definition: context.h:37
A mutable version of CTransaction.
Definition: transaction.h:377
Wallet errors.
Definition: protocol.h:71
CPubKey pubkey
Definition: pubkey.h:348
RPCHelpMan getreceivedbyaddress()
Definition: coins.cpp:81
RPCHelpMan getbalance()
Definition: coins.cpp:163
RPCHelpMan listaddressgroupings()
Definition: addresses.cpp:158
RPCHelpMan removeprunedfunds()
Definition: backup.cpp:377
An encapsulated private key.
Definition: key.h:34
Span< const CRPCCommand > GetWalletRPCCommands()
Definition: wallet.cpp:1108
A Span is an object that can refer to a contiguous sequence of objects.
Definition: span.h:97
RPCErrorCode
Bitcoin RPC error codes.
Definition: protocol.h:24
RPCHelpMan backupwallet()
Definition: backup.cpp:1893
CKey DecodeSecret(const std::string &str)
Definition: key_io.cpp:213
RPCHelpMan bumpfee()
Definition: spend.cpp:1196
static RPCHelpMan migratewallet()
Definition: wallet.cpp:757
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:383
RPCHelpMan getnewaddress()
Definition: addresses.cpp:21
RPCHelpMan getbalances()
Definition: coins.cpp:427
virtual bool rpcEnableDeprecated(const std::string &method)=0
Check if deprecated RPC is enabled.
static RPCHelpMan listwallets()
Definition: wallet.cpp:185
COutPoint prevout
Definition: transaction.h:69
static RPCHelpMan createwalletdescriptor()
Definition: wallet.cpp:933
const CHDChain & GetHDChain() const
ArgsManager * args
Definition: context.h:39
CKeyID seed_id
seed hash160
Definition: walletdb.h:102
RPCHelpMan getrawchangeaddress()
Definition: addresses.cpp:73
std::string EncodeExtKey(const CExtKey &key)
Definition: key_io.cpp:283
static RPCHelpMan upgradewallet()
Definition: wallet.cpp:586
Wrapper for UniValue::VType, which includes typeAny: Used to denote don&#39;t care type.
Definition: util.h:79
void AppendLastProcessedBlock(UniValue &entry, const CWallet &wallet)
Definition: util.cpp:166
std::shared_ptr< CWallet > GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
Definition: util.cpp:57
static const std::map< uint64_t, std::string > WALLET_FLAG_CAVEATS
Definition: wallet.cpp:27
bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest &request, std::string &wallet_name)
Definition: util.cpp:47
Error parsing or validating structure in raw format.
Definition: protocol.h:46
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:46
RPCHelpMan addmultisigaddress()
Definition: addresses.cpp:218
bool IsValid() const
Check whether this private key is valid.
Definition: key.h:123
RPCHelpMan settxfee()
Definition: spend.cpp:418