LCOV - code coverage report
Current view: top level - src/wallet/rpc - wallet.cpp (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 98.4 % 617 607
Test Date: 2025-08-25 05:11:47 Functions: 100.0 % 23 23
Branches: 51.6 % 2280 1176

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

Generated by: LCOV version 2.0-1