Bitcoin Core  27.99.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 <config/bitcoin-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 scriptPubKey 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 
178  UniValue result(UniValue::VOBJ);
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 wallet directory or .dat file."},
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  HelpExampleCli("loadwallet", "\"test.dat\"")
238  + HelpExampleRpc("loadwallet", "\"test.dat\"")
239  },
240  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
241 {
242  WalletContext& context = EnsureWalletContext(request.context);
243  const std::string name(request.params[0].get_str());
244 
245  DatabaseOptions options;
246  DatabaseStatus status;
247  ReadDatabaseArgs(*context.args, options);
248  options.require_existing = true;
249  bilingual_str error;
250  std::vector<bilingual_str> warnings;
251  std::optional<bool> load_on_start = request.params[1].isNull() ? std::nullopt : std::optional<bool>(request.params[1].get_bool());
252 
253  {
254  LOCK(context.wallets_mutex);
255  if (std::any_of(context.wallets.begin(), context.wallets.end(), [&name](const auto& wallet) { return wallet->GetName() == name; })) {
256  throw JSONRPCError(RPC_WALLET_ALREADY_LOADED, "Wallet \"" + name + "\" is already loaded.");
257  }
258  }
259 
260  std::shared_ptr<CWallet> const wallet = LoadWallet(context, name, load_on_start, options, status, error, warnings);
261 
262  HandleWalletError(wallet, status, error);
263 
265  obj.pushKV("name", wallet->GetName());
266  PushWarnings(warnings, obj);
267 
268  return obj;
269 },
270  };
271 }
272 
274 {
275  std::string flags;
276  for (auto& it : WALLET_FLAG_MAP)
277  if (it.second & MUTABLE_WALLET_FLAGS)
278  flags += (flags == "" ? "" : ", ") + it.first;
279 
280  return RPCHelpMan{"setwalletflag",
281  "\nChange the state of the given wallet flag for a wallet.\n",
282  {
283  {"flag", RPCArg::Type::STR, RPCArg::Optional::NO, "The name of the flag to change. Current available flags: " + flags},
284  {"value", RPCArg::Type::BOOL, RPCArg::Default{true}, "The new state."},
285  },
286  RPCResult{
287  RPCResult::Type::OBJ, "", "",
288  {
289  {RPCResult::Type::STR, "flag_name", "The name of the flag that was modified"},
290  {RPCResult::Type::BOOL, "flag_state", "The new state of the flag"},
291  {RPCResult::Type::STR, "warnings", /*optional=*/true, "Any warnings associated with the change"},
292  }
293  },
294  RPCExamples{
295  HelpExampleCli("setwalletflag", "avoid_reuse")
296  + HelpExampleRpc("setwalletflag", "\"avoid_reuse\"")
297  },
298  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
299 {
300  std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
301  if (!pwallet) return UniValue::VNULL;
302 
303  std::string flag_str = request.params[0].get_str();
304  bool value = request.params[1].isNull() || request.params[1].get_bool();
305 
306  if (!WALLET_FLAG_MAP.count(flag_str)) {
307  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Unknown wallet flag: %s", flag_str));
308  }
309 
310  auto flag = WALLET_FLAG_MAP.at(flag_str);
311 
312  if (!(flag & MUTABLE_WALLET_FLAGS)) {
313  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is immutable: %s", flag_str));
314  }
315 
317 
318  if (pwallet->IsWalletFlagSet(flag) == value) {
319  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is already set to %s: %s", value ? "true" : "false", flag_str));
320  }
321 
322  res.pushKV("flag_name", flag_str);
323  res.pushKV("flag_state", value);
324 
325  if (value) {
326  pwallet->SetWalletFlag(flag);
327  } else {
328  pwallet->UnsetWalletFlag(flag);
329  }
330 
331  if (flag && value && WALLET_FLAG_CAVEATS.count(flag)) {
332  res.pushKV("warnings", WALLET_FLAG_CAVEATS.at(flag));
333  }
334 
335  return res;
336 },
337  };
338 }
339 
341 {
342  return RPCHelpMan{
343  "createwallet",
344  "\nCreates and loads a new wallet.\n",
345  {
346  {"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."},
347  {"disable_private_keys", RPCArg::Type::BOOL, RPCArg::Default{false}, "Disable the possibility of private keys (only watchonlys are possible in this mode)."},
348  {"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."},
349  {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."},
350  {"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."},
351  {"descriptors", RPCArg::Type::BOOL, RPCArg::Default{true}, "Create a native descriptor wallet. The wallet will use descriptors internally to handle address creation."
352  " 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"
353  " support for creating and opening legacy wallets will be removed in the future."},
354  {"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."},
355  {"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."},
356  },
357  RPCResult{
358  RPCResult::Type::OBJ, "", "",
359  {
360  {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."},
361  {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to creating and loading the wallet.",
362  {
363  {RPCResult::Type::STR, "", ""},
364  }},
365  }
366  },
367  RPCExamples{
368  HelpExampleCli("createwallet", "\"testwallet\"")
369  + HelpExampleRpc("createwallet", "\"testwallet\"")
370  + HelpExampleCliNamed("createwallet", {{"wallet_name", "descriptors"}, {"avoid_reuse", true}, {"descriptors", true}, {"load_on_startup", true}})
371  + HelpExampleRpcNamed("createwallet", {{"wallet_name", "descriptors"}, {"avoid_reuse", true}, {"descriptors", true}, {"load_on_startup", true}})
372  },
373  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
374 {
375  WalletContext& context = EnsureWalletContext(request.context);
376  uint64_t flags = 0;
377  if (!request.params[1].isNull() && request.params[1].get_bool()) {
379  }
380 
381  if (!request.params[2].isNull() && request.params[2].get_bool()) {
383  }
384  SecureString passphrase;
385  passphrase.reserve(100);
386  std::vector<bilingual_str> warnings;
387  if (!request.params[3].isNull()) {
388  passphrase = std::string_view{request.params[3].get_str()};
389  if (passphrase.empty()) {
390  // Empty string means unencrypted
391  warnings.emplace_back(Untranslated("Empty string given as passphrase, wallet will not be encrypted."));
392  }
393  }
394 
395  if (!request.params[4].isNull() && request.params[4].get_bool()) {
397  }
398  if (self.Arg<bool>("descriptors")) {
399 #ifndef USE_SQLITE
400  throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without sqlite support (required for descriptor wallets)");
401 #endif
403  } else {
404  if (!context.chain->rpcEnableDeprecated("create_bdb")) {
405  throw JSONRPCError(RPC_WALLET_ERROR, "BDB wallet creation is deprecated and will be removed in a future release."
406  " In this release it can be re-enabled temporarily with the -deprecatedrpc=create_bdb setting.");
407  }
408  }
409  if (!request.params[7].isNull() && request.params[7].get_bool()) {
410 #ifdef ENABLE_EXTERNAL_SIGNER
412 #else
413  throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without external signing support (required for external signing)");
414 #endif
415  }
416 
417 #ifndef USE_BDB
418  if (!(flags & WALLET_FLAG_DESCRIPTORS)) {
419  throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without bdb support (required for legacy wallets)");
420  }
421 #endif
422 
423  DatabaseOptions options;
424  DatabaseStatus status;
425  ReadDatabaseArgs(*context.args, options);
426  options.require_create = true;
427  options.create_flags = flags;
428  options.create_passphrase = passphrase;
429  bilingual_str error;
430  std::optional<bool> load_on_start = request.params[6].isNull() ? std::nullopt : std::optional<bool>(request.params[6].get_bool());
431  const std::shared_ptr<CWallet> wallet = CreateWallet(context, request.params[0].get_str(), load_on_start, options, status, error, warnings);
432  if (!wallet) {
433  RPCErrorCode code = status == DatabaseStatus::FAILED_ENCRYPT ? RPC_WALLET_ENCRYPTION_FAILED : RPC_WALLET_ERROR;
434  throw JSONRPCError(code, error.original);
435  }
436 
438  obj.pushKV("name", wallet->GetName());
439  PushWarnings(warnings, obj);
440 
441  return obj;
442 },
443  };
444 }
445 
447 {
448  return RPCHelpMan{"unloadwallet",
449  "Unloads the wallet referenced by the request endpoint, otherwise unloads the wallet specified in the argument.\n"
450  "Specifying the wallet name on a wallet endpoint is invalid.",
451  {
452  {"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."},
453  {"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."},
454  },
456  {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to unloading the wallet.",
457  {
458  {RPCResult::Type::STR, "", ""},
459  }},
460  }},
461  RPCExamples{
462  HelpExampleCli("unloadwallet", "wallet_name")
463  + HelpExampleRpc("unloadwallet", "wallet_name")
464  },
465  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
466 {
467  std::string wallet_name;
468  if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
469  if (!(request.params[0].isNull() || request.params[0].get_str() == wallet_name)) {
470  throw JSONRPCError(RPC_INVALID_PARAMETER, "RPC endpoint wallet and wallet_name parameter specify different wallets");
471  }
472  } else {
473  wallet_name = request.params[0].get_str();
474  }
475 
476  WalletContext& context = EnsureWalletContext(request.context);
477  std::shared_ptr<CWallet> wallet = GetWallet(context, wallet_name);
478  if (!wallet) {
479  throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
480  }
481 
482  std::vector<bilingual_str> warnings;
483  {
484  WalletRescanReserver reserver(*wallet);
485  if (!reserver.reserve()) {
486  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
487  }
488 
489  // Release the "main" shared pointer and prevent further notifications.
490  // Note that any attempt to load the same wallet would fail until the wallet
491  // is destroyed (see CheckUniqueFileid).
492  std::optional<bool> load_on_start{self.MaybeArg<bool>("load_on_startup")};
493  if (!RemoveWallet(context, wallet, load_on_start, warnings)) {
494  throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded");
495  }
496  }
497 
498  UnloadWallet(std::move(wallet));
499 
500  UniValue result(UniValue::VOBJ);
501  PushWarnings(warnings, result);
502 
503  return result;
504 },
505  };
506 }
507 
509 {
510  return RPCHelpMan{"sethdseed",
511  "\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"
512  "HD will have a new HD seed set so that new keys added to the keypool will be derived from this new seed.\n"
513  "\nNote that you will need to MAKE A NEW BACKUP of your wallet after setting the HD wallet seed." + HELP_REQUIRING_PASSPHRASE +
514  "Note: This command is only compatible with legacy wallets.\n",
515  {
516  {"newkeypool", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether to flush old unused addresses, including change addresses, from the keypool and regenerate it.\n"
517  "If true, the next address from getnewaddress and change address from getrawchangeaddress will be from this new seed.\n"
518  "If false, addresses (including change addresses if the wallet already had HD Chain Split enabled) from the existing\n"
519  "keypool will be used until it has been depleted."},
520  {"seed", RPCArg::Type::STR, RPCArg::DefaultHint{"random seed"}, "The WIF private key to use as the new HD seed.\n"
521  "The seed value can be retrieved using the dumpwallet command. It is the private key marked hdseed=1"},
522  },
524  RPCExamples{
525  HelpExampleCli("sethdseed", "")
526  + HelpExampleCli("sethdseed", "false")
527  + HelpExampleCli("sethdseed", "true \"wifkey\"")
528  + HelpExampleRpc("sethdseed", "true, \"wifkey\"")
529  },
530  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
531 {
532  std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
533  if (!pwallet) return UniValue::VNULL;
534 
535  LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet, true);
536 
537  if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
538  throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed to a wallet with private keys disabled");
539  }
540 
541  LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
542 
543  // Do not do anything to non-HD wallets
544  if (!pwallet->CanSupportFeature(FEATURE_HD)) {
545  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");
546  }
547 
548  EnsureWalletIsUnlocked(*pwallet);
549 
550  bool flush_key_pool = true;
551  if (!request.params[0].isNull()) {
552  flush_key_pool = request.params[0].get_bool();
553  }
554 
555  CPubKey master_pub_key;
556  if (request.params[1].isNull()) {
557  master_pub_key = spk_man.GenerateNewSeed();
558  } else {
559  CKey key = DecodeSecret(request.params[1].get_str());
560  if (!key.IsValid()) {
561  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
562  }
563 
564  if (HaveKey(spk_man, key)) {
565  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Already have this key (either as an HD seed or as a loose private key)");
566  }
567 
568  master_pub_key = spk_man.DeriveNewSeed(key);
569  }
570 
571  spk_man.SetHDSeed(master_pub_key);
572  if (flush_key_pool) spk_man.NewKeyPool();
573 
574  return UniValue::VNULL;
575 },
576  };
577 }
578 
580 {
581  return RPCHelpMan{"upgradewallet",
582  "\nUpgrade the wallet. Upgrades to the latest version if no version number is specified.\n"
583  "New keys may be generated and a new wallet backup will need to be made.",
584  {
585  {"version", RPCArg::Type::NUM, RPCArg::Default{int{FEATURE_LATEST}}, "The version number to upgrade to. Default is the latest wallet version."}
586  },
587  RPCResult{
588  RPCResult::Type::OBJ, "", "",
589  {
590  {RPCResult::Type::STR, "wallet_name", "Name of wallet this operation was performed on"},
591  {RPCResult::Type::NUM, "previous_version", "Version of wallet before this operation"},
592  {RPCResult::Type::NUM, "current_version", "Version of wallet after this operation"},
593  {RPCResult::Type::STR, "result", /*optional=*/true, "Description of result, if no error"},
594  {RPCResult::Type::STR, "error", /*optional=*/true, "Error message (if there is one)"}
595  },
596  },
597  RPCExamples{
598  HelpExampleCli("upgradewallet", "169900")
599  + HelpExampleRpc("upgradewallet", "169900")
600  },
601  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
602 {
603  std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
604  if (!pwallet) return UniValue::VNULL;
605 
606  EnsureWalletIsUnlocked(*pwallet);
607 
608  int version = 0;
609  if (!request.params[0].isNull()) {
610  version = request.params[0].getInt<int>();
611  }
612  bilingual_str error;
613  const int previous_version{pwallet->GetVersion()};
614  const bool wallet_upgraded{pwallet->UpgradeWallet(version, error)};
615  const int current_version{pwallet->GetVersion()};
616  std::string result;
617 
618  if (wallet_upgraded) {
619  if (previous_version == current_version) {
620  result = "Already at latest version. Wallet version unchanged.";
621  } else {
622  result = strprintf("Wallet upgraded successfully from version %i to version %i.", previous_version, current_version);
623  }
624  }
625 
627  obj.pushKV("wallet_name", pwallet->GetName());
628  obj.pushKV("previous_version", previous_version);
629  obj.pushKV("current_version", current_version);
630  if (!result.empty()) {
631  obj.pushKV("result", result);
632  } else {
633  CHECK_NONFATAL(!error.empty());
634  obj.pushKV("error", error.original);
635  }
636  return obj;
637 },
638  };
639 }
640 
642 {
643  return RPCHelpMan{"simulaterawtransaction",
644  "\nCalculate the balance change resulting in the signing and broadcasting of the given transaction(s).\n",
645  {
646  {"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "An array of hex strings of raw transactions.\n",
647  {
649  },
650  },
652  {
653  {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses (see RPC importaddress)"},
654  },
655  },
656  },
657  RPCResult{
658  RPCResult::Type::OBJ, "", "",
659  {
660  {RPCResult::Type::STR_AMOUNT, "balance_change", "The wallet balance change (negative means decrease)."},
661  }
662  },
663  RPCExamples{
664  HelpExampleCli("simulaterawtransaction", "[\"myhex\"]")
665  + HelpExampleRpc("simulaterawtransaction", "[\"myhex\"]")
666  },
667  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
668 {
669  const std::shared_ptr<const CWallet> rpc_wallet = GetWalletForJSONRPCRequest(request);
670  if (!rpc_wallet) return UniValue::VNULL;
671  const CWallet& wallet = *rpc_wallet;
672 
673  LOCK(wallet.cs_wallet);
674 
675  UniValue include_watchonly(UniValue::VNULL);
676  if (request.params[1].isObject()) {
677  UniValue options = request.params[1];
678  RPCTypeCheckObj(options,
679  {
680  {"include_watchonly", UniValueType(UniValue::VBOOL)},
681  },
682  true, true);
683 
684  include_watchonly = options["include_watchonly"];
685  }
686 
688  if (ParseIncludeWatchonly(include_watchonly, wallet)) {
689  filter |= ISMINE_WATCH_ONLY;
690  }
691 
692  const auto& txs = request.params[0].get_array();
693  CAmount changes{0};
694  std::map<COutPoint, CAmount> new_utxos; // UTXO:s that were made available in transaction array
695  std::set<COutPoint> spent;
696 
697  for (size_t i = 0; i < txs.size(); ++i) {
699  if (!DecodeHexTx(mtx, txs[i].get_str(), /* try_no_witness */ true, /* try_witness */ true)) {
700  throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Transaction hex string decoding failure.");
701  }
702 
703  // Fetch previous transactions (inputs)
704  std::map<COutPoint, Coin> coins;
705  for (const CTxIn& txin : mtx.vin) {
706  coins[txin.prevout]; // Create empty map entry keyed by prevout.
707  }
708  wallet.chain().findCoins(coins);
709 
710  // Fetch debit; we are *spending* these; if the transaction is signed and
711  // broadcast, we will lose everything in these
712  for (const auto& txin : mtx.vin) {
713  const auto& outpoint = txin.prevout;
714  if (spent.count(outpoint)) {
715  throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction(s) are spending the same output more than once");
716  }
717  if (new_utxos.count(outpoint)) {
718  changes -= new_utxos.at(outpoint);
719  new_utxos.erase(outpoint);
720  } else {
721  if (coins.at(outpoint).IsSpent()) {
722  throw JSONRPCError(RPC_INVALID_PARAMETER, "One or more transaction inputs are missing or have been spent already");
723  }
724  changes -= wallet.GetDebit(txin, filter);
725  }
726  spent.insert(outpoint);
727  }
728 
729  // Iterate over outputs; we are *receiving* these, if the wallet considers
730  // them "mine"; if the transaction is signed and broadcast, we will receive
731  // everything in these
732  // Also populate new_utxos in case these are spent in later transactions
733 
734  const auto& hash = mtx.GetHash();
735  for (size_t i = 0; i < mtx.vout.size(); ++i) {
736  const auto& txout = mtx.vout[i];
737  bool is_mine = 0 < (wallet.IsMine(txout) & filter);
738  changes += new_utxos[COutPoint(hash, i)] = is_mine ? txout.nValue : 0;
739  }
740  }
741 
742  UniValue result(UniValue::VOBJ);
743  result.pushKV("balance_change", ValueFromAmount(changes));
744 
745  return result;
746 }
747  };
748 }
749 
751 {
752  return RPCHelpMan{"migratewallet",
753  "\nMigrate the wallet to a descriptor wallet.\n"
754  "A new wallet backup will need to be made.\n"
755  "\nThe migration process will create a backup of the wallet before migrating. This backup\n"
756  "file will be named <wallet name>-<timestamp>.legacy.bak and can be found in the directory\n"
757  "for this wallet. In the event of an incorrect migration, the backup can be restored using restorewallet."
758  "\nEncrypted wallets must have the passphrase provided as an argument to this call.\n"
759  "\nThis RPC may take a long time to complete. Increasing the RPC client timeout is recommended.",
760  {
761  {"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."},
762  {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "The wallet passphrase"},
763  },
764  RPCResult{
765  RPCResult::Type::OBJ, "", "",
766  {
767  {RPCResult::Type::STR, "wallet_name", "The name of the primary migrated wallet"},
768  {RPCResult::Type::STR, "watchonly_name", /*optional=*/true, "The name of the migrated wallet containing the watchonly scripts"},
769  {RPCResult::Type::STR, "solvables_name", /*optional=*/true, "The name of the migrated wallet containing solvable but not watched scripts"},
770  {RPCResult::Type::STR, "backup_path", "The location of the backup of the original wallet"},
771  }
772  },
773  RPCExamples{
774  HelpExampleCli("migratewallet", "")
775  + HelpExampleRpc("migratewallet", "")
776  },
777  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
778  {
779  std::string wallet_name;
780  if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
781  if (!(request.params[0].isNull() || request.params[0].get_str() == wallet_name)) {
782  throw JSONRPCError(RPC_INVALID_PARAMETER, "RPC endpoint wallet and wallet_name parameter specify different wallets");
783  }
784  } else {
785  if (request.params[0].isNull()) {
786  throw JSONRPCError(RPC_INVALID_PARAMETER, "Either RPC endpoint wallet or wallet_name parameter must be provided");
787  }
788  wallet_name = request.params[0].get_str();
789  }
790 
791  SecureString wallet_pass;
792  wallet_pass.reserve(100);
793  if (!request.params[1].isNull()) {
794  wallet_pass = std::string_view{request.params[1].get_str()};
795  }
796 
797  WalletContext& context = EnsureWalletContext(request.context);
798  util::Result<MigrationResult> res = MigrateLegacyToDescriptor(wallet_name, wallet_pass, context);
799  if (!res) {
800  throw JSONRPCError(RPC_WALLET_ERROR, util::ErrorString(res).original);
801  }
802 
804  r.pushKV("wallet_name", res->wallet_name);
805  if (res->watchonly_wallet) {
806  r.pushKV("watchonly_name", res->watchonly_wallet->GetName());
807  }
808  if (res->solvables_wallet) {
809  r.pushKV("solvables_name", res->solvables_wallet->GetName());
810  }
811  r.pushKV("backup_path", res->backup_path.utf8string());
812 
813  return r;
814  },
815  };
816 }
817 
819 {
820  return RPCHelpMan{
821  "gethdkeys",
822  "\nList all BIP 32 HD keys in the wallet and which descriptors use them.\n",
823  {
825  {"active_only", RPCArg::Type::BOOL, RPCArg::Default{false}, "Show the keys for only active descriptors"},
826  {"private", RPCArg::Type::BOOL, RPCArg::Default{false}, "Show private keys"}
827  }},
828  },
830  {
831  {RPCResult::Type::OBJ, "", "", {
832  {RPCResult::Type::STR, "xpub", "The extended public key"},
833  {RPCResult::Type::BOOL, "has_private", "Whether the wallet has the private key for this xpub"},
834  {RPCResult::Type::STR, "xprv", /*optional=*/true, "The extended private key if \"private\" is true"},
835  {RPCResult::Type::ARR, "descriptors", "Array of descriptor objects that use this HD key",
836  {
837  {RPCResult::Type::OBJ, "", "", {
838  {RPCResult::Type::STR, "desc", "Descriptor string representation"},
839  {RPCResult::Type::BOOL, "active", "Whether this descriptor is currently used to generate new addresses"},
840  }},
841  }},
842  }},
843  }
844  }},
845  RPCExamples{
846  HelpExampleCli("gethdkeys", "") + HelpExampleRpc("gethdkeys", "")
847  + HelpExampleCliNamed("gethdkeys", {{"active_only", "true"}, {"private", "true"}}) + HelpExampleRpcNamed("gethdkeys", {{"active_only", "true"}, {"private", "true"}})
848  },
849  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
850  {
851  const std::shared_ptr<const CWallet> wallet = GetWalletForJSONRPCRequest(request);
852  if (!wallet) return UniValue::VNULL;
853 
854  if (!wallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
855  throw JSONRPCError(RPC_WALLET_ERROR, "gethdkeys is not available for non-descriptor wallets");
856  }
857 
858  LOCK(wallet->cs_wallet);
859 
860  UniValue options{request.params[0].isNull() ? UniValue::VOBJ : request.params[0]};
861  const bool active_only{options.exists("active_only") ? options["active_only"].get_bool() : false};
862  const bool priv{options.exists("private") ? options["private"].get_bool() : false};
863  if (priv) {
865  }
866 
867 
868  std::set<ScriptPubKeyMan*> spkms;
869  if (active_only) {
870  spkms = wallet->GetActiveScriptPubKeyMans();
871  } else {
872  spkms = wallet->GetAllScriptPubKeyMans();
873  }
874 
875  std::map<CExtPubKey, std::set<std::tuple<std::string, bool, bool>>> wallet_xpubs;
876  std::map<CExtPubKey, CExtKey> wallet_xprvs;
877  for (auto* spkm : spkms) {
878  auto* desc_spkm{dynamic_cast<DescriptorScriptPubKeyMan*>(spkm)};
879  CHECK_NONFATAL(desc_spkm);
880  LOCK(desc_spkm->cs_desc_man);
881  WalletDescriptor w_desc = desc_spkm->GetWalletDescriptor();
882 
883  // Retrieve the pubkeys from the descriptor
884  std::set<CPubKey> desc_pubkeys;
885  std::set<CExtPubKey> desc_xpubs;
886  w_desc.descriptor->GetPubKeys(desc_pubkeys, desc_xpubs);
887  for (const CExtPubKey& xpub : desc_xpubs) {
888  std::string desc_str;
889  bool ok = desc_spkm->GetDescriptorString(desc_str, false);
890  CHECK_NONFATAL(ok);
891  wallet_xpubs[xpub].emplace(desc_str, wallet->IsActiveScriptPubKeyMan(*spkm), desc_spkm->HasPrivKey(xpub.pubkey.GetID()));
892  if (std::optional<CKey> key = priv ? desc_spkm->GetKey(xpub.pubkey.GetID()) : std::nullopt) {
893  wallet_xprvs[xpub] = CExtKey(xpub, *key);
894  }
895  }
896  }
897 
898  UniValue response(UniValue::VARR);
899  for (const auto& [xpub, descs] : wallet_xpubs) {
900  bool has_xprv = false;
901  UniValue descriptors(UniValue::VARR);
902  for (const auto& [desc, active, has_priv] : descs) {
904  d.pushKV("desc", desc);
905  d.pushKV("active", active);
906  has_xprv |= has_priv;
907 
908  descriptors.push_back(std::move(d));
909  }
910  UniValue xpub_info(UniValue::VOBJ);
911  xpub_info.pushKV("xpub", EncodeExtPubKey(xpub));
912  xpub_info.pushKV("has_private", has_xprv);
913  if (priv) {
914  xpub_info.pushKV("xprv", EncodeExtKey(wallet_xprvs.at(xpub)));
915  }
916  xpub_info.pushKV("descriptors", std::move(descriptors));
917 
918  response.push_back(std::move(xpub_info));
919  }
920 
921  return response;
922  },
923  };
924 }
925 
927 {
928  return RPCHelpMan{"createwalletdescriptor",
929  "Creates the wallet's descriptor for the given address type. "
930  "The address type must be one that the wallet does not already have a descriptor for."
932  {
933  {"type", RPCArg::Type::STR, RPCArg::Optional::NO, "The address type the descriptor will produce. Options are \"legacy\", \"p2sh-segwit\", \"bech32\", and \"bech32m\"."},
935  {"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)"},
936  {"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"},
937  }},
938  },
939  RPCResult{
940  RPCResult::Type::OBJ, "", "",
941  {
942  {RPCResult::Type::ARR, "descs", "The public descriptors that were added to the wallet",
943  {{RPCResult::Type::STR, "", ""}}
944  }
945  },
946  },
947  RPCExamples{
948  HelpExampleCli("createwalletdescriptor", "bech32m")
949  + HelpExampleRpc("createwalletdescriptor", "bech32m")
950  },
951  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
952  {
953  std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
954  if (!pwallet) return UniValue::VNULL;
955 
956  // Make sure wallet is a descriptor wallet
957  if (!pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
958  throw JSONRPCError(RPC_WALLET_ERROR, "createwalletdescriptor is not available for non-descriptor wallets");
959  }
960 
961  std::optional<OutputType> output_type = ParseOutputType(request.params[0].get_str());
962  if (!output_type) {
963  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[0].get_str()));
964  }
965 
966  UniValue options{request.params[1].isNull() ? UniValue::VOBJ : request.params[1]};
967  UniValue internal_only{options["internal"]};
968  UniValue hdkey{options["hdkey"]};
969 
970  std::vector<bool> internals;
971  if (internal_only.isNull()) {
972  internals.push_back(false);
973  internals.push_back(true);
974  } else {
975  internals.push_back(internal_only.get_bool());
976  }
977 
978  LOCK(pwallet->cs_wallet);
979  EnsureWalletIsUnlocked(*pwallet);
980 
981  CExtPubKey xpub;
982  if (hdkey.isNull()) {
983  std::set<CExtPubKey> active_xpubs = pwallet->GetActiveHDPubKeys();
984  if (active_xpubs.size() != 1) {
985  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to determine which HD key to use from active descriptors. Please specify with 'hdkey'");
986  }
987  xpub = *active_xpubs.begin();
988  } else {
989  xpub = DecodeExtPubKey(hdkey.get_str());
990  if (!xpub.pubkey.IsValid()) {
991  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to parse HD key. Please provide a valid xpub");
992  }
993  }
994 
995  std::optional<CKey> key = pwallet->GetKey(xpub.pubkey.GetID());
996  if (!key) {
997  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Private key for %s is not known", EncodeExtPubKey(xpub)));
998  }
999  CExtKey active_hdkey(xpub, *key);
1000 
1001  std::vector<std::reference_wrapper<DescriptorScriptPubKeyMan>> spkms;
1002  WalletBatch batch{pwallet->GetDatabase()};
1003  for (bool internal : internals) {
1004  WalletDescriptor w_desc = GenerateWalletDescriptor(xpub, *output_type, internal);
1005  uint256 w_id = DescriptorID(*w_desc.descriptor);
1006  if (!pwallet->GetScriptPubKeyMan(w_id)) {
1007  spkms.emplace_back(pwallet->SetupDescriptorScriptPubKeyMan(batch, active_hdkey, *output_type, internal));
1008  }
1009  }
1010  if (spkms.empty()) {
1011  throw JSONRPCError(RPC_WALLET_ERROR, "Descriptor already exists");
1012  }
1013 
1014  // Fetch each descspkm from the wallet in order to get the descriptor strings
1015  UniValue descs{UniValue::VARR};
1016  for (const auto& spkm : spkms) {
1017  std::string desc_str;
1018  bool ok = spkm.get().GetDescriptorString(desc_str, false);
1019  CHECK_NONFATAL(ok);
1020  descs.push_back(desc_str);
1021  }
1023  out.pushKV("descs", std::move(descs));
1024  return out;
1025  }
1026  };
1027 }
1028 
1029 // addresses
1040 #ifdef ENABLE_EXTERNAL_SIGNER
1042 #endif // ENABLE_EXTERNAL_SIGNER
1043 
1044 // backup
1058 
1059 // coins
1068 
1069 // encryption
1074 
1075 // spend
1082 RPCHelpMan send();
1087 
1088 // signmessage
1090 
1091 // transactions
1100 
1102 {
1103  static const CRPCCommand commands[]{
1104  {"rawtransactions", &fundrawtransaction},
1105  {"wallet", &abandontransaction},
1106  {"wallet", &abortrescan},
1107  {"wallet", &addmultisigaddress},
1108  {"wallet", &backupwallet},
1109  {"wallet", &bumpfee},
1110  {"wallet", &psbtbumpfee},
1111  {"wallet", &createwallet},
1112  {"wallet", &createwalletdescriptor},
1113  {"wallet", &restorewallet},
1114  {"wallet", &dumpprivkey},
1115  {"wallet", &dumpwallet},
1116  {"wallet", &encryptwallet},
1117  {"wallet", &getaddressesbylabel},
1118  {"wallet", &getaddressinfo},
1119  {"wallet", &getbalance},
1120  {"wallet", &gethdkeys},
1121  {"wallet", &getnewaddress},
1122  {"wallet", &getrawchangeaddress},
1123  {"wallet", &getreceivedbyaddress},
1124  {"wallet", &getreceivedbylabel},
1125  {"wallet", &gettransaction},
1126  {"wallet", &getunconfirmedbalance},
1127  {"wallet", &getbalances},
1128  {"wallet", &getwalletinfo},
1129  {"wallet", &importaddress},
1130  {"wallet", &importdescriptors},
1131  {"wallet", &importmulti},
1132  {"wallet", &importprivkey},
1133  {"wallet", &importprunedfunds},
1134  {"wallet", &importpubkey},
1135  {"wallet", &importwallet},
1136  {"wallet", &keypoolrefill},
1137  {"wallet", &listaddressgroupings},
1138  {"wallet", &listdescriptors},
1139  {"wallet", &listlabels},
1140  {"wallet", &listlockunspent},
1141  {"wallet", &listreceivedbyaddress},
1142  {"wallet", &listreceivedbylabel},
1143  {"wallet", &listsinceblock},
1144  {"wallet", &listtransactions},
1145  {"wallet", &listunspent},
1146  {"wallet", &listwalletdir},
1147  {"wallet", &listwallets},
1148  {"wallet", &loadwallet},
1149  {"wallet", &lockunspent},
1150  {"wallet", &migratewallet},
1151  {"wallet", &newkeypool},
1152  {"wallet", &removeprunedfunds},
1153  {"wallet", &rescanblockchain},
1154  {"wallet", &send},
1155  {"wallet", &sendmany},
1156  {"wallet", &sendtoaddress},
1157  {"wallet", &sethdseed},
1158  {"wallet", &setlabel},
1159  {"wallet", &settxfee},
1160  {"wallet", &setwalletflag},
1161  {"wallet", &signmessage},
1162  {"wallet", &signrawtransactionwithwallet},
1163  {"wallet", &simulaterawtransaction},
1164  {"wallet", &sendall},
1165  {"wallet", &unloadwallet},
1166  {"wallet", &upgradewallet},
1167  {"wallet", &walletcreatefundedpsbt},
1168 #ifdef ENABLE_EXTERNAL_SIGNER
1169  {"wallet", &walletdisplayaddress},
1170 #endif // ENABLE_EXTERNAL_SIGNER
1171  {"wallet", &walletlock},
1172  {"wallet", &walletpassphrase},
1173  {"wallet", &walletpassphrasechange},
1174  {"wallet", &walletprocesspsbt},
1175  };
1176  return commands;
1177 }
1178 } // namespace wallet
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
int flags
Definition: bitcoin-tx.cpp:533
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:73
An encapsulated private key.
Definition: key.h:33
const std::byte * end() const
Definition: key.h:118
bool IsValid() const
Check whether this private key is valid.
Definition: key.h:121
bool IsCompressed() const
Check whether the public key corresponding to this private key is (to be) compressed.
Definition: key.h:124
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:182
void Set(const T pbegin, const T pend, bool fCompressedIn)
Initialize using begin and end iterators to byte data.
Definition: key.h:101
const std::byte * begin() const
Definition: key.h:117
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:24
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:29
An encapsulated public key.
Definition: pubkey.h:34
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:164
bool IsValid() const
Definition: pubkey.h:189
An input of a transaction.
Definition: transaction.h:67
COutPoint prevout
Definition: transaction.h:69
RecursiveMutex cs_KeyStore
An interface to be implemented by keystores that support signing.
A Span is an object that can refer to a contiguous sequence of objects.
Definition: span.h:98
void push_back(UniValue val)
Definition: univalue.cpp:104
@ VNULL
Definition: univalue.h:24
@ VOBJ
Definition: univalue.h:24
@ VARR
Definition: univalue.h:24
@ VBOOL
Definition: univalue.h:24
bool isNull() const
Definition: univalue.h:79
void pushKV(std::string key, UniValue val)
Definition: univalue.cpp:126
constexpr bool IsNull() const
Definition: uint256.h:44
std::string GetHex() const
Definition: uint256.cpp:11
virtual bool rpcEnableDeprecated(const std::string &method)=0
Check if deprecated RPC is enabled.
256-bit opaque blob.
Definition: uint256.h:127
CKeyID seed_id
seed hash160
Definition: walletdb.h:102
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:303
const CHDChain & GetHDChain() const
bool NewKeyPool()
Mark old keypool keys as used, and generate all new keys.
CPubKey DeriveNewSeed(const CKey &key)
void SetHDSeed(const CPubKey &key)
Access to the wallet database.
Definition: walletdb.h:191
Descriptor with some wallet metadata.
Definition: walletutil.h:85
std::shared_ptr< Descriptor > descriptor
Definition: walletutil.h:87
RAII object to check and reserve a wallet rescan.
Definition: wallet.h:1076
bool reserve(bool with_passphrase=false)
Definition: wallet.h:1086
UniValue ValueFromAmount(const CAmount amount)
Definition: core_write.cpp:26
bool DecodeHexTx(CMutableTransaction &tx, const std::string &hex_tx, bool try_no_witness=false, bool try_witness=true)
Definition: core_read.cpp:196
const std::string CURRENCY_UNIT
Definition: feerate.h:17
std::string EncodeExtKey(const CExtKey &key)
Definition: key_io.cpp:276
CExtPubKey DecodeExtPubKey(const std::string &str)
Definition: key_io.cpp:240
CKey DecodeSecret(const std::string &str)
Definition: key_io.cpp:209
std::string EncodeExtPubKey(const CExtPubKey &key)
Definition: key_io.cpp:253
void ReadDatabaseArgs(const ArgsManager &args, DBOptions &options)
bilingual_str ErrorString(const Result< T > &result)
Definition: result.h:93
static RPCHelpMan sethdseed()
Definition: wallet.cpp:508
void UnloadWallet(std::shared_ptr< CWallet > &&wallet)
Explicitly unload and delete the wallet.
Definition: wallet.cpp:243
void ReadDatabaseArgs(const ArgsManager &args, DatabaseOptions &options)
Definition: db.cpp:145
Balance GetBalance(const CWallet &wallet, const int min_depth, bool avoid_reuse)
Definition: receive.cpp:293
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:364
RPCHelpMan walletlock()
Definition: encrypt.cpp:174
static RPCHelpMan loadwallet()
Definition: wallet.cpp:216
std::shared_ptr< CWallet > GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
Definition: util.cpp:73
RPCHelpMan listreceivedbyaddress()
std::vector< std::shared_ptr< CWallet > > GetWallets(WalletContext &context)
Definition: wallet.cpp:182
RPCHelpMan keypoolrefill()
Definition: addresses.cpp:336
RPCHelpMan removeprunedfunds()
Definition: backup.cpp:377
RPCHelpMan listlockunspent()
Definition: coins.cpp:374
static const RPCResult RESULT_LAST_PROCESSED_BLOCK
Definition: util.h:28
RPCHelpMan importwallet()
Definition: backup.cpp:488
bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest &request, std::string &wallet_name)
Definition: util.cpp:63
RPCHelpMan importmulti()
Definition: backup.cpp:1236
RPCHelpMan walletprocesspsbt()
Definition: spend.cpp:1573
void HandleWalletError(const std::shared_ptr< CWallet > wallet, DatabaseStatus &status, bilingual_str &error)
Definition: util.cpp:155
void EnsureWalletIsUnlocked(const CWallet &wallet)
Definition: util.cpp:97
static RPCHelpMan getwalletinfo()
Definition: wallet.cpp:42
RPCHelpMan backupwallet()
Definition: backup.cpp:1847
static RPCHelpMan listwalletdir()
Definition: wallet.cpp:148
RPCHelpMan walletpassphrase()
Definition: encrypt.cpp:11
const std::string HELP_REQUIRING_PASSPHRASE
Definition: util.cpp:21
RPCHelpMan psbtbumpfee()
Definition: spend.cpp:1192
std::vector< fs::path > ListDatabases(const fs::path &wallet_dir)
Recursively list database paths in directory.
Definition: db.cpp:22
RPCHelpMan getreceivedbyaddress()
Definition: coins.cpp:81
RPCHelpMan walletdisplayaddress()
Definition: addresses.cpp:781
RPCHelpMan getbalance()
Definition: coins.cpp:163
RPCHelpMan importaddress()
Definition: backup.cpp:219
RPCHelpMan importprunedfunds()
Definition: backup.cpp:321
LegacyScriptPubKeyMan & EnsureLegacyScriptPubKeyMan(CWallet &wallet, bool also_create)
Definition: util.cpp:114
RPCHelpMan simulaterawtransaction()
Definition: wallet.cpp:641
static RPCHelpMan setwalletflag()
Definition: wallet.cpp:273
RPCHelpMan importprivkey()
Definition: backup.cpp:116
RPCHelpMan dumpprivkey()
Definition: backup.cpp:636
RPCHelpMan walletcreatefundedpsbt()
Definition: spend.cpp:1656
bool RemoveWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet, std::optional< bool > load_on_start)
Definition: wallet.cpp:176
RPCHelpMan addmultisigaddress()
Definition: addresses.cpp:218
WalletContext & EnsureWalletContext(const std::any &context)
Definition: util.cpp:104
RPCHelpMan listaddressgroupings()
Definition: addresses.cpp:158
RPCHelpMan walletpassphrasechange()
Definition: encrypt.cpp:115
std::underlying_type< isminetype >::type isminefilter
used for bitflags of isminetype
Definition: wallet.h:48
fs::path GetWalletDir()
Get the path of the wallet directory.
Definition: walletutil.cpp:13
RPCHelpMan abandontransaction()
RPCHelpMan settxfee()
Definition: spend.cpp:418
bool HaveKey(const SigningProvider &wallet, const CKey &key)
Checks if a CKey is in the given CWallet compressed or otherwise.
Definition: wallet.cpp:35
RPCHelpMan listdescriptors()
Definition: backup.cpp:1734
RPCHelpMan listtransactions()
RPCHelpMan signrawtransactionwithwallet()
Definition: spend.cpp:870
util::Result< MigrationResult > MigrateLegacyToDescriptor(const std::string &wallet_name, const SecureString &passphrase, WalletContext &context)
Do all steps to migrate a legacy wallet to a descriptor wallet.
Definition: wallet.cpp:4374
RPCHelpMan importpubkey()
Definition: backup.cpp:409
static RPCHelpMan listwallets()
Definition: wallet.cpp:185
RPCHelpMan signmessage()
Definition: signmessage.cpp:14
static RPCHelpMan upgradewallet()
Definition: wallet.cpp:579
static constexpr int64_t UNKNOWN_TIME
Constant representing an unknown spkm creation time.
RPCHelpMan sendall()
Definition: spend.cpp:1313
static const std::map< std::string, WalletFlags > WALLET_FLAG_MAP
Definition: wallet.h:165
RPCHelpMan dumpwallet()
Definition: backup.cpp:683
static RPCHelpMan unloadwallet()
Definition: wallet.cpp:446
RPCHelpMan listsinceblock()
RPCHelpMan bumpfee()
Definition: spend.cpp:1191
RPCHelpMan lockunspent()
Definition: coins.cpp:238
RPCHelpMan abortrescan()
RPCHelpMan restorewallet()
Definition: backup.cpp:1881
RPCHelpMan listlabels()
Definition: addresses.cpp:725
@ ISMINE_SPENDABLE
Definition: types.h:44
@ ISMINE_WATCH_ONLY
Definition: types.h:43
void AppendLastProcessedBlock(UniValue &entry, const CWallet &wallet)
Definition: util.cpp:182
bool ParseIncludeWatchonly(const UniValue &include_watchonly, const CWallet &wallet)
Used by RPC commands that have an include_watchonly parameter.
Definition: util.cpp:52
RPCHelpMan getreceivedbylabel()
Definition: coins.cpp:122
RPCHelpMan importdescriptors()
Definition: backup.cpp:1577
RPCHelpMan getbalances()
Definition: coins.cpp:427
RPCHelpMan getrawchangeaddress()
Definition: addresses.cpp:73
RPCHelpMan setlabel()
Definition: addresses.cpp:120
static RPCHelpMan createwallet()
Definition: wallet.cpp:340
RPCHelpMan sendmany()
Definition: spend.cpp:324
@ FEATURE_HD_SPLIT
Definition: walletutil.h:24
@ FEATURE_HD
Definition: walletutil.h:22
@ FEATURE_LATEST
Definition: walletutil.h:30
RPCHelpMan getaddressinfo()
Definition: addresses.cpp:519
RPCHelpMan encryptwallet()
Definition: encrypt.cpp:216
RPCHelpMan gettransaction()
RPCHelpMan getaddressesbylabel()
Definition: addresses.cpp:665
RPCHelpMan fundrawtransaction()
Definition: spend.cpp:736
static const std::map< uint64_t, std::string > WALLET_FLAG_CAVEATS
Definition: wallet.cpp:27
RPCHelpMan listunspent()
Definition: coins.cpp:497
Span< const CRPCCommand > GetWalletRPCCommands()
Definition: wallet.cpp:1101
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:377
static RPCHelpMan migratewallet()
Definition: wallet.cpp:750
RPCHelpMan rescanblockchain()
@ WALLET_FLAG_EXTERNAL_SIGNER
Indicates that the wallet needs an external signer.
Definition: walletutil.h:77
@ WALLET_FLAG_AVOID_REUSE
Definition: walletutil.h:42
@ WALLET_FLAG_DESCRIPTORS
Indicate that this wallet supports DescriptorScriptPubKeyMan.
Definition: walletutil.h:74
@ WALLET_FLAG_DISABLE_PRIVATE_KEYS
Definition: walletutil.h:51
@ WALLET_FLAG_BLANK_WALLET
Flag set when a wallet contains no HD seed and no private keys, scripts, addresses,...
Definition: walletutil.h:71
RPCHelpMan gethdkeys()
Definition: wallet.cpp:818
static constexpr uint64_t MUTABLE_WALLET_FLAGS
Definition: wallet.h:162
RPCHelpMan getnewaddress()
Definition: addresses.cpp:21
RPCHelpMan listreceivedbylabel()
RPCHelpMan newkeypool()
Definition: addresses.cpp:380
std::shared_ptr< CWallet > GetWallet(WalletContext &context, const std::string &name)
Definition: wallet.cpp:195
RPCHelpMan getunconfirmedbalance()
Definition: coins.cpp:215
RPCHelpMan send()
Definition: spend.cpp:1194
RPCHelpMan sendtoaddress()
Definition: spend.cpp:230
DatabaseStatus
Definition: db.h:204
static RPCHelpMan createwalletdescriptor()
Definition: wallet.cpp:926
WalletDescriptor GenerateWalletDescriptor(const CExtPubKey &master_key, const OutputType &addr_type, bool internal)
Definition: walletutil.cpp:49
std::shared_ptr< CWallet > wallet
std::optional< OutputType > ParseOutputType(const std::string &type)
Definition: outputtype.cpp:24
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:70
const char * name
Definition: rest.cpp:49
RPCErrorCode
Bitcoin RPC error codes.
Definition: protocol.h:25
@ RPC_MISC_ERROR
General application defined errors.
Definition: protocol.h:40
@ RPC_WALLET_ENCRYPTION_FAILED
Failed to encrypt the wallet.
Definition: protocol.h:79
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:44
@ RPC_WALLET_ERROR
Wallet errors.
Definition: protocol.h:72
@ RPC_WALLET_ALREADY_LOADED
This same wallet is already loaded.
Definition: protocol.h:83
@ RPC_WALLET_NOT_FOUND
Invalid wallet specified.
Definition: protocol.h:81
@ 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:168
std::string HelpExampleRpcNamed(const std::string &methodname, const RPCArgList &args)
Definition: util.cpp:192
void PushWarnings(const UniValue &warnings, UniValue &obj)
Push warning messages to an RPC "warnings" field as a JSON array of strings.
Definition: util.cpp:1373
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:186
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
void RPCTypeCheckObj(const UniValue &o, const std::map< std::string, UniValueType > &typesExpected, bool fAllowNull, bool fStrict)
Definition: util.cpp:56
std::string HelpExampleCliNamed(const std::string &methodname, const RPCArgList &args)
Definition: util.cpp:173
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:58
Definition: key.h:209
CPubKey pubkey
Definition: pubkey.h:348
A mutable version of CTransaction.
Definition: transaction.h:378
std::vector< CTxOut > vout
Definition: transaction.h:380
Txid GetHash() const
Compute the hash of this CMutableTransaction.
Definition: transaction.cpp:69
std::vector< CTxIn > vin
Definition: transaction.h:379
@ 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:206
@ 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_HEX
Special string with only hex chars.
@ STR_AMOUNT
Special string to represent a floating point amount.
Wrapper for UniValue::VType, which includes typeAny: Used to denote don't care type.
Definition: util.h:79
Bilingual messages:
Definition: translation.h:18
bool empty() const
Definition: translation.h:29
std::string original
Definition: translation.h:19
bool require_existing
Definition: db.h:191
SecureString create_passphrase
Definition: db.h:195
uint64_t create_flags
Definition: db.h:194
WalletContext struct containing references to state shared between CWallet instances,...
Definition: context.h:36
interfaces::Chain * chain
Definition: context.h:37
ArgsManager * args
Definition: context.h:39
#define LOCK2(cs1, cs2)
Definition: sync.h:258
#define LOCK(cs)
Definition: sync.h:257
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1161
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:48