LCOV - code coverage report
Current view: top level - src/wallet/rpc - wallet.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 17 616 2.8 %
Date: 2024-01-03 14:57:27 Functions: 0 32 0.0 %
Branches: 21 2256 0.9 %

           Branch data     Line data    Source code
       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 <core_io.h>
       7                 :            : #include <key_io.h>
       8                 :            : #include <rpc/server.h>
       9                 :            : #include <rpc/util.h>
      10                 :            : #include <util/translation.h>
      11                 :            : #include <wallet/context.h>
      12                 :            : #include <wallet/receive.h>
      13                 :            : #include <wallet/rpc/wallet.h>
      14                 :            : #include <wallet/rpc/util.h>
      15                 :            : #include <wallet/wallet.h>
      16                 :            : #include <wallet/walletutil.h>
      17                 :            : 
      18                 :            : #include <optional>
      19                 :            : 
      20                 :            : #include <univalue.h>
      21                 :            : 
      22                 :            : 
      23                 :            : namespace wallet {
      24                 :            : 
      25         [ +  - ]:          2 : static const std::map<uint64_t, std::string> WALLET_FLAG_CAVEATS{
      26         [ +  - ]:          2 :     {WALLET_FLAG_AVOID_REUSE,
      27                 :          2 :      "You need to rescan the blockchain in order to correctly mark used "
      28 [ +  - ][ +  - ]:          6 :      "destinations in the past. Until this is done, some destinations may "
         [ +  - ][ -  + ]
                 [ #  # ]
      29 [ +  - ][ +  - ]:          2 :      "be considered unused, even if the opposite is the case."},
                 [ +  - ]
      30 [ +  - ][ +  - ]:          2 : };
                 [ +  - ]
      31                 :            : 
      32                 :            : /** Checks if a CKey is in the given CWallet compressed or otherwise*/
      33                 :          0 : bool HaveKey(const SigningProvider& wallet, const CKey& key)
      34                 :            : {
      35                 :          0 :     CKey key2;
      36 [ #  # ][ #  # ]:          0 :     key2.Set(key.begin(), key.end(), !key.IsCompressed());
         [ #  # ][ #  # ]
      37 [ #  # ][ #  # ]:          0 :     return wallet.HaveKey(key.GetPubKey().GetID()) || wallet.HaveKey(key2.GetPubKey().GetID());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      38                 :          0 : }
      39                 :            : 
      40                 :          0 : static RPCHelpMan getwalletinfo()
      41                 :            : {
      42 [ #  # ][ #  # ]:          0 :     return RPCHelpMan{"getwalletinfo",
         [ #  # ][ #  # ]
      43         [ #  # ]:          0 :                 "Returns an object containing various wallet state info.\n",
      44                 :          0 :                 {},
      45 [ #  # ][ #  # ]:          0 :                 RPCResult{
      46 [ #  # ][ #  # ]:          0 :                     RPCResult::Type::OBJ, "", "",
      47         [ #  # ]:          0 :                     {
      48                 :          0 :                         {
      49 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::STR, "walletname", "the wallet name"},
                 [ #  # ]
      50 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::NUM, "walletversion", "the wallet version"},
                 [ #  # ]
      51 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::STR, "format", "the database format (bdb or sqlite)"},
                 [ #  # ]
      52 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::STR_AMOUNT, "balance", "DEPRECATED. Identical to getbalances().mine.trusted"},
                 [ #  # ]
      53 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::STR_AMOUNT, "unconfirmed_balance", "DEPRECATED. Identical to getbalances().mine.untrusted_pending"},
                 [ #  # ]
      54 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::STR_AMOUNT, "immature_balance", "DEPRECATED. Identical to getbalances().mine.immature"},
                 [ #  # ]
      55 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::NUM, "txcount", "the total number of transactions in the wallet"},
                 [ #  # ]
      56 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::NUM_TIME, "keypoololdest", /*optional=*/true, "the " + UNIX_EPOCH_TIME + " of the oldest pre-generated key in the key pool. Legacy wallets only."},
         [ #  # ][ #  # ]
      57 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::NUM, "keypoolsize", "how many new keys are pre-generated (only counts external keys)"},
                 [ #  # ]
      58 [ #  # ][ #  # ]:          0 :                         {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)"},
                 [ #  # ]
      59 [ #  # ][ #  # ]:          0 :                         {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)"},
         [ #  # ][ #  # ]
      60 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::STR_AMOUNT, "paytxfee", "the transaction fee configuration, set in " + CURRENCY_UNIT + "/kvB"},
         [ #  # ][ #  # ]
      61 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::STR_HEX, "hdseedid", /*optional=*/true, "the Hash160 of the HD seed (only present when HD is enabled)"},
                 [ #  # ]
      62 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::BOOL, "private_keys_enabled", "false if privatekeys are disabled for this wallet (enforced watch-only wallet)"},
                 [ #  # ]
      63 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::BOOL, "avoid_reuse", "whether this wallet tracks clean/dirty coins in terms of reuse"},
                 [ #  # ]
      64 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::OBJ, "scanning", "current scanning details, or false if no scan is in progress",
                 [ #  # ]
      65         [ #  # ]:          0 :                         {
      66 [ #  # ][ #  # ]:          0 :                             {RPCResult::Type::NUM, "duration", "elapsed seconds since scan start"},
                 [ #  # ]
      67 [ #  # ][ #  # ]:          0 :                             {RPCResult::Type::NUM, "progress", "scanning progress percentage [0.0, 1.0]"},
                 [ #  # ]
      68                 :            :                         }, /*skip_type_check=*/true},
      69 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::BOOL, "descriptors", "whether this wallet uses descriptors for scriptPubKey management"},
                 [ #  # ]
      70 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::BOOL, "external_signer", "whether this wallet is configured to use an external signer such as a hardware wallet"},
                 [ #  # ]
      71 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::BOOL, "blank", "Whether this wallet intentionally does not contain any keys, scripts, or descriptors"},
                 [ #  # ]
      72 [ #  # ][ #  # ]:          0 :                         {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."},
                 [ #  # ]
      73         [ #  # ]:          0 :                         RESULT_LAST_PROCESSED_BLOCK,
      74                 :            :                     }},
      75                 :            :                 },
      76         [ #  # ]:          0 :                 RPCExamples{
      77 [ #  # ][ #  # ]:          0 :                     HelpExampleCli("getwalletinfo", "")
                 [ #  # ]
      78 [ #  # ][ #  # ]:          0 :             + HelpExampleRpc("getwalletinfo", "")
         [ #  # ][ #  # ]
      79                 :            :                 },
      80                 :          0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
      81                 :            : {
      82                 :          0 :     const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
      83 [ #  # ][ #  # ]:          0 :     if (!pwallet) return UniValue::VNULL;
      84                 :            : 
      85                 :            :     // Make sure the results are valid at least up to the most recent block
      86                 :            :     // the user could have gotten from another RPC command prior to now
      87         [ #  # ]:          0 :     pwallet->BlockUntilSyncedToCurrentChain();
      88                 :            : 
      89 [ #  # ][ #  # ]:          0 :     LOCK(pwallet->cs_wallet);
      90                 :            : 
      91         [ #  # ]:          0 :     UniValue obj(UniValue::VOBJ);
      92                 :            : 
      93         [ #  # ]:          0 :     size_t kpExternalSize = pwallet->KeypoolCountExternalKeys();
      94         [ #  # ]:          0 :     const auto bal = GetBalance(*pwallet);
      95 [ #  # ][ #  # ]:          0 :     obj.pushKV("walletname", pwallet->GetName());
                 [ #  # ]
      96 [ #  # ][ #  # ]:          0 :     obj.pushKV("walletversion", pwallet->GetVersion());
         [ #  # ][ #  # ]
      97 [ #  # ][ #  # ]:          0 :     obj.pushKV("format", pwallet->GetDatabase().Format());
         [ #  # ][ #  # ]
                 [ #  # ]
      98 [ #  # ][ #  # ]:          2 :     obj.pushKV("balance", ValueFromAmount(bal.m_mine_trusted));
                 [ #  # ]
      99 [ #  # ][ #  # ]:          0 :     obj.pushKV("unconfirmed_balance", ValueFromAmount(bal.m_mine_untrusted_pending));
                 [ #  # ]
     100 [ #  # ][ #  # ]:          0 :     obj.pushKV("immature_balance", ValueFromAmount(bal.m_mine_immature));
                 [ #  # ]
     101 [ #  # ][ #  # ]:          0 :     obj.pushKV("txcount",       (int)pwallet->mapWallet.size());
                 [ #  # ]
     102         [ #  # ]:          0 :     const auto kp_oldest = pwallet->GetOldestKeyPoolTime();
     103         [ #  # ]:          0 :     if (kp_oldest.has_value()) {
     104 [ #  # ][ #  # ]:          0 :         obj.pushKV("keypoololdest", kp_oldest.value());
         [ #  # ][ #  # ]
     105                 :          0 :     }
     106 [ #  # ][ #  # ]:          2 :     obj.pushKV("keypoolsize", (int64_t)kpExternalSize);
                 [ #  # ]
     107                 :            : 
     108         [ #  # ]:          0 :     LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
     109         [ #  # ]:          0 :     if (spk_man) {
     110         [ #  # ]:          0 :         CKeyID seed_id = spk_man->GetHDChain().seed_id;
     111 [ #  # ][ #  # ]:          0 :         if (!seed_id.IsNull()) {
     112 [ #  # ][ #  # ]:          0 :             obj.pushKV("hdseedid", seed_id.GetHex());
         [ #  # ][ #  # ]
     113                 :          0 :         }
     114                 :          0 :     }
     115                 :            : 
     116 [ #  # ][ #  # ]:          0 :     if (pwallet->CanSupportFeature(FEATURE_HD_SPLIT)) {
     117 [ #  # ][ #  # ]:          0 :         obj.pushKV("keypoolsize_hd_internal",   (int64_t)(pwallet->GetKeyPoolSize() - kpExternalSize));
         [ #  # ][ #  # ]
     118                 :          0 :     }
     119 [ #  # ][ #  # ]:          0 :     if (pwallet->IsCrypted()) {
     120 [ #  # ][ #  # ]:          0 :         obj.pushKV("unlocked_until", pwallet->nRelockTime);
                 [ #  # ]
     121                 :          0 :     }
     122 [ #  # ][ #  # ]:          0 :     obj.pushKV("paytxfee", ValueFromAmount(pwallet->m_pay_tx_fee.GetFeePerK()));
         [ #  # ][ #  # ]
     123 [ #  # ][ #  # ]:          0 :     obj.pushKV("private_keys_enabled", !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
         [ #  # ][ #  # ]
     124 [ #  # ][ #  # ]:          0 :     obj.pushKV("avoid_reuse", pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE));
         [ #  # ][ #  # ]
     125 [ #  # ][ #  # ]:          0 :     if (pwallet->IsScanning()) {
     126         [ #  # ]:          0 :         UniValue scanning(UniValue::VOBJ);
     127 [ #  # ][ #  # ]:          0 :         scanning.pushKV("duration", Ticks<std::chrono::seconds>(pwallet->ScanningDuration()));
         [ #  # ][ #  # ]
                 [ #  # ]
     128 [ #  # ][ #  # ]:          0 :         scanning.pushKV("progress", pwallet->ScanningProgress());
         [ #  # ][ #  # ]
     129 [ #  # ][ #  # ]:          0 :         obj.pushKV("scanning", scanning);
                 [ #  # ]
     130                 :          0 :     } else {
     131 [ #  # ][ #  # ]:          0 :         obj.pushKV("scanning", false);
                 [ #  # ]
     132                 :            :     }
     133 [ #  # ][ #  # ]:          0 :     obj.pushKV("descriptors", pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
         [ #  # ][ #  # ]
     134 [ #  # ][ #  # ]:          0 :     obj.pushKV("external_signer", pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER));
         [ #  # ][ #  # ]
     135 [ #  # ][ #  # ]:          0 :     obj.pushKV("blank", pwallet->IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET));
         [ #  # ][ #  # ]
     136 [ #  # ][ #  # ]:          0 :     if (int64_t birthtime = pwallet->GetBirthTime(); birthtime != UNKNOWN_TIME) {
     137 [ #  # ][ #  # ]:          0 :         obj.pushKV("birthtime", birthtime);
                 [ #  # ]
     138                 :          0 :     }
     139                 :            : 
     140         [ #  # ]:          0 :     AppendLastProcessedBlock(obj, *pwallet);
     141                 :          0 :     return obj;
     142         [ #  # ]:          0 : },
     143                 :            :     };
     144                 :          0 : }
     145                 :            : 
     146                 :          0 : static RPCHelpMan listwalletdir()
     147                 :            : {
     148 [ #  # ][ #  # ]:          0 :     return RPCHelpMan{"listwalletdir",
         [ #  # ][ #  # ]
                 [ #  # ]
     149         [ #  # ]:          0 :                 "Returns a list of wallets in the wallet directory.\n",
     150                 :          0 :                 {},
     151 [ #  # ][ #  # ]:          0 :                 RPCResult{
     152 [ #  # ][ #  # ]:          0 :                     RPCResult::Type::OBJ, "", "",
     153         [ #  # ]:          0 :                     {
     154 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::ARR, "wallets", "",
                 [ #  # ]
     155         [ #  # ]:          0 :                         {
     156 [ #  # ][ #  # ]:          0 :                             {RPCResult::Type::OBJ, "", "",
                 [ #  # ]
     157         [ #  # ]:          0 :                             {
     158 [ #  # ][ #  # ]:          0 :                                 {RPCResult::Type::STR, "name", "The wallet name"},
                 [ #  # ]
     159                 :            :                             }},
     160                 :            :                         }},
     161                 :            :                     }
     162                 :            :                 },
     163 [ +  - ][ #  # ]:          2 :                 RPCExamples{
     164 [ +  - ][ #  # ]:          2 :                     HelpExampleCli("listwalletdir", "")
         [ #  # ][ #  # ]
     165 [ +  - ][ #  # ]:          2 :             + HelpExampleRpc("listwalletdir", "")
         [ #  # ][ #  # ]
                 [ #  # ]
     166         [ +  - ]:          2 :                 },
     167         [ +  - ]:          2 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     168         [ +  - ]:          2 : {
     169 [ +  - ][ #  # ]:          2 :     UniValue wallets(UniValue::VARR);
     170 [ +  - ][ #  # ]:          2 :     for (const auto& path : ListDatabases(GetWalletDir())) {
         [ #  # ][ #  # ]
     171         [ #  # ]:          0 :         UniValue wallet(UniValue::VOBJ);
     172 [ #  # ][ #  # ]:          0 :         wallet.pushKV("name", path.utf8string());
         [ #  # ][ #  # ]
     173 [ #  # ][ #  # ]:          0 :         wallets.push_back(wallet);
     174                 :          0 :     }
     175                 :            : 
     176         [ #  # ]:          0 :     UniValue result(UniValue::VOBJ);
     177 [ #  # ][ #  # ]:          0 :     result.pushKV("wallets", wallets);
                 [ #  # ]
     178                 :          0 :     return result;
     179         [ #  # ]:          0 : },
     180                 :            :     };
     181                 :          0 : }
     182                 :            : 
     183                 :          0 : static RPCHelpMan listwallets()
     184                 :            : {
     185 [ #  # ][ #  # ]:          0 :     return RPCHelpMan{"listwallets",
                 [ #  # ]
     186         [ #  # ]:          0 :                 "Returns a list of currently loaded wallets.\n"
     187                 :            :                 "For full information on the wallet, use \"getwalletinfo\"\n",
     188                 :          0 :                 {},
     189 [ #  # ][ #  # ]:          0 :                 RPCResult{
     190 [ #  # ][ #  # ]:          0 :                     RPCResult::Type::ARR, "", "",
     191         [ #  # ]:          0 :                     {
     192 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::STR, "walletname", "the wallet name"},
                 [ #  # ]
     193                 :            :                     }
     194                 :            :                 },
     195         [ #  # ]:          0 :                 RPCExamples{
     196 [ #  # ][ #  # ]:          0 :                     HelpExampleCli("listwallets", "")
                 [ #  # ]
     197 [ #  # ][ #  # ]:          0 :             + HelpExampleRpc("listwallets", "")
         [ #  # ][ #  # ]
     198                 :            :                 },
     199                 :          0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     200                 :            : {
     201         [ #  # ]:          0 :     UniValue obj(UniValue::VARR);
     202                 :            : 
     203         [ #  # ]:          0 :     WalletContext& context = EnsureWalletContext(request.context);
     204 [ #  # ][ #  # ]:          0 :     for (const std::shared_ptr<CWallet>& wallet : GetWallets(context)) {
     205         [ #  # ]:          0 :         LOCK(wallet->cs_wallet);
     206 [ #  # ][ #  # ]:          0 :         obj.push_back(wallet->GetName());
     207                 :          0 :     }
     208                 :            : 
     209                 :          0 :     return obj;
     210         [ #  # ]:          0 : },
     211                 :            :     };
     212                 :          0 : }
     213                 :            : 
     214                 :          0 : static RPCHelpMan loadwallet()
     215                 :            : {
     216 [ #  # ][ #  # ]:          0 :     return RPCHelpMan{"loadwallet",
         [ #  # ][ #  # ]
                 [ #  # ]
     217         [ #  # ]:          0 :                 "\nLoads a wallet from a wallet file or directory."
     218                 :            :                 "\nNote that all wallet command-line options used when starting bitcoind will be"
     219                 :            :                 "\napplied to the new wallet.\n",
     220         [ #  # ]:          0 :                 {
     221 [ #  # ][ #  # ]:          0 :                     {"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet directory or .dat file."},
                 [ #  # ]
     222 [ #  # ][ #  # ]:          0 :                     {"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."},
                 [ #  # ]
     223                 :            :                 },
     224 [ #  # ][ #  # ]:          0 :                 RPCResult{
     225 [ #  # ][ #  # ]:          0 :                     RPCResult::Type::OBJ, "", "",
     226         [ #  # ]:          0 :                     {
     227 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::STR, "name", "The wallet name if loaded successfully."},
                 [ #  # ]
     228 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to loading the wallet.",
                 [ #  # ]
     229         [ #  # ]:          0 :                         {
     230 [ #  # ][ #  # ]:          0 :                             {RPCResult::Type::STR, "", ""},
                 [ #  # ]
     231                 :            :                         }},
     232                 :            :                     }
     233                 :            :                 },
     234         [ #  # ]:          0 :                 RPCExamples{
     235 [ #  # ][ #  # ]:          0 :                     HelpExampleCli("loadwallet", "\"test.dat\"")
                 [ #  # ]
     236 [ #  # ][ #  # ]:          0 :             + HelpExampleRpc("loadwallet", "\"test.dat\"")
         [ #  # ][ #  # ]
     237                 :            :                 },
     238                 :          0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     239                 :            : {
     240                 :          0 :     WalletContext& context = EnsureWalletContext(request.context);
     241                 :          0 :     const std::string name(request.params[0].get_str());
     242                 :            : 
     243                 :          0 :     DatabaseOptions options;
     244                 :            :     DatabaseStatus status;
     245         [ #  # ]:          0 :     ReadDatabaseArgs(*context.args, options);
     246                 :          0 :     options.require_existing = true;
     247                 :          0 :     bilingual_str error;
     248                 :          0 :     std::vector<bilingual_str> warnings;
     249 [ #  # ][ #  # ]:          0 :     std::optional<bool> load_on_start = request.params[1].isNull() ? std::nullopt : std::optional<bool>(request.params[1].get_bool());
         [ #  # ][ #  # ]
     250                 :            : 
     251                 :            :     {
     252 [ #  # ][ #  # ]:          0 :         LOCK(context.wallets_mutex);
     253 [ #  # ][ #  # ]:          0 :         if (std::any_of(context.wallets.begin(), context.wallets.end(), [&name](const auto& wallet) { return wallet->GetName() == name; })) {
     254 [ #  # ][ #  # ]:          0 :             throw JSONRPCError(RPC_WALLET_ALREADY_LOADED, "Wallet \"" + name + "\" is already loaded.");
         [ #  # ][ #  # ]
                 [ #  # ]
     255                 :            :         }
     256                 :          0 :     }
     257                 :            : 
     258         [ #  # ]:          0 :     std::shared_ptr<CWallet> const wallet = LoadWallet(context, name, load_on_start, options, status, error, warnings);
     259                 :            : 
     260         [ #  # ]:          0 :     HandleWalletError(wallet, status, error);
     261                 :            : 
     262         [ #  # ]:          0 :     UniValue obj(UniValue::VOBJ);
     263 [ #  # ][ #  # ]:          0 :     obj.pushKV("name", wallet->GetName());
                 [ #  # ]
     264         [ #  # ]:          0 :     PushWarnings(warnings, obj);
     265                 :            : 
     266                 :          0 :     return obj;
     267 [ +  - ][ #  # ]:          2 : },
     268                 :            :     };
     269                 :          0 : }
     270                 :            : 
     271                 :          0 : static RPCHelpMan setwalletflag()
     272                 :            : {
     273                 :          0 :             std::string flags;
     274         [ #  # ]:          0 :             for (auto& it : WALLET_FLAG_MAP)
     275         [ #  # ]:          0 :                 if (it.second & MUTABLE_WALLET_FLAGS)
     276 [ #  # ][ #  # ]:          0 :                     flags += (flags == "" ? "" : ", ") + it.first;
                 [ #  # ]
     277                 :            : 
     278 [ #  # ][ #  # ]:          0 :     return RPCHelpMan{"setwalletflag",
         [ #  # ][ #  # ]
     279         [ #  # ]:          0 :                 "\nChange the state of the given wallet flag for a wallet.\n",
     280         [ #  # ]:          0 :                 {
     281 [ #  # ][ #  # ]:          0 :                     {"flag", RPCArg::Type::STR, RPCArg::Optional::NO, "The name of the flag to change. Current available flags: " + flags},
                 [ #  # ]
     282 [ #  # ][ #  # ]:          0 :                     {"value", RPCArg::Type::BOOL, RPCArg::Default{true}, "The new state."},
         [ #  # ][ #  # ]
     283                 :            :                 },
     284 [ #  # ][ #  # ]:          0 :                 RPCResult{
     285 [ #  # ][ #  # ]:          0 :                     RPCResult::Type::OBJ, "", "",
     286         [ #  # ]:          0 :                     {
     287 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::STR, "flag_name", "The name of the flag that was modified"},
                 [ #  # ]
     288 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::BOOL, "flag_state", "The new state of the flag"},
                 [ #  # ]
     289 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::STR, "warnings", /*optional=*/true, "Any warnings associated with the change"},
                 [ #  # ]
     290                 :            :                     }
     291                 :            :                 },
     292         [ #  # ]:          0 :                 RPCExamples{
     293 [ #  # ][ #  # ]:          0 :                     HelpExampleCli("setwalletflag", "avoid_reuse")
                 [ #  # ]
     294 [ #  # ][ #  # ]:          0 :                   + HelpExampleRpc("setwalletflag", "\"avoid_reuse\"")
         [ #  # ][ #  # ]
     295                 :            :                 },
     296                 :          0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     297                 :            : {
     298                 :          0 :     std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
     299 [ #  # ][ #  # ]:          0 :     if (!pwallet) return UniValue::VNULL;
     300                 :            : 
     301 [ #  # ][ #  # ]:          0 :     std::string flag_str = request.params[0].get_str();
                 [ #  # ]
     302 [ #  # ][ #  # ]:          0 :     bool value = request.params[1].isNull() || request.params[1].get_bool();
         [ #  # ][ #  # ]
     303                 :            : 
     304 [ #  # ][ #  # ]:          0 :     if (!WALLET_FLAG_MAP.count(flag_str)) {
     305 [ #  # ][ #  # ]:          0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Unknown wallet flag: %s", flag_str));
                 [ #  # ]
     306                 :            :     }
     307                 :            : 
     308         [ #  # ]:          0 :     auto flag = WALLET_FLAG_MAP.at(flag_str);
     309                 :            : 
     310         [ #  # ]:          0 :     if (!(flag & MUTABLE_WALLET_FLAGS)) {
     311 [ #  # ][ #  # ]:          0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is immutable: %s", flag_str));
                 [ #  # ]
     312                 :            :     }
     313                 :            : 
     314         [ #  # ]:          0 :     UniValue res(UniValue::VOBJ);
     315                 :            : 
     316 [ #  # ][ #  # ]:          0 :     if (pwallet->IsWalletFlagSet(flag) == value) {
     317 [ #  # ][ #  # ]:          0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is already set to %s: %s", value ? "true" : "false", flag_str));
                 [ #  # ]
     318                 :            :     }
     319                 :            : 
     320 [ #  # ][ #  # ]:          0 :     res.pushKV("flag_name", flag_str);
                 [ #  # ]
     321 [ #  # ][ #  # ]:          0 :     res.pushKV("flag_state", value);
                 [ #  # ]
     322                 :            : 
     323         [ #  # ]:          0 :     if (value) {
     324         [ #  # ]:          0 :         pwallet->SetWalletFlag(flag);
     325                 :          0 :     } else {
     326         [ #  # ]:          0 :         pwallet->UnsetWalletFlag(flag);
     327                 :            :     }
     328                 :            : 
     329 [ #  # ][ #  # ]:          0 :     if (flag && value && WALLET_FLAG_CAVEATS.count(flag)) {
         [ #  # ][ #  # ]
     330 [ #  # ][ #  # ]:          0 :         res.pushKV("warnings", WALLET_FLAG_CAVEATS.at(flag));
         [ #  # ][ #  # ]
     331                 :          0 :     }
     332                 :            : 
     333                 :          0 :     return res;
     334         [ #  # ]:          0 : },
     335                 :            :     };
     336                 :          0 : }
     337                 :            : 
     338                 :          0 : static RPCHelpMan createwallet()
     339                 :            : {
     340 [ #  # ][ #  # ]:          0 :     return RPCHelpMan{
         [ #  # ][ #  # ]
     341         [ #  # ]:          0 :         "createwallet",
     342         [ #  # ]:          0 :         "\nCreates and loads a new wallet.\n",
     343         [ #  # ]:          0 :         {
     344 [ #  # ][ #  # ]:          0 :             {"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."},
                 [ #  # ]
     345 [ #  # ][ #  # ]:          0 :             {"disable_private_keys", RPCArg::Type::BOOL, RPCArg::Default{false}, "Disable the possibility of private keys (only watchonlys are possible in this mode)."},
         [ #  # ][ #  # ]
     346 [ #  # ][ #  # ]:          0 :             {"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."},
         [ #  # ][ #  # ]
     347 [ #  # ][ #  # ]:          0 :             {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."},
                 [ #  # ]
     348 [ #  # ][ #  # ]:          0 :             {"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."},
         [ #  # ][ #  # ]
     349 [ #  # ][ #  # ]:          0 :             {"descriptors", RPCArg::Type::BOOL, RPCArg::Default{true}, "Create a native descriptor wallet. The wallet will use descriptors internally to handle address creation."
         [ #  # ][ #  # ]
     350                 :            :                                                                        " 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"
     351                 :            :                                                                        " support for creating and opening legacy wallets will be removed in the future."},
     352 [ #  # ][ #  # ]:          0 :             {"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."},
                 [ #  # ]
     353 [ #  # ][ #  # ]:          0 :             {"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."},
         [ #  # ][ #  # ]
     354                 :            :         },
     355 [ #  # ][ #  # ]:          0 :         RPCResult{
     356 [ #  # ][ #  # ]:          0 :             RPCResult::Type::OBJ, "", "",
     357         [ #  # ]:          0 :             {
     358 [ #  # ][ #  # ]:          0 :                 {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."},
                 [ #  # ]
     359 [ #  # ][ #  # ]:          0 :                 {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to creating and loading the wallet.",
                 [ #  # ]
     360         [ #  # ]:          0 :                 {
     361 [ #  # ][ #  # ]:          0 :                     {RPCResult::Type::STR, "", ""},
                 [ #  # ]
     362                 :            :                 }},
     363                 :            :             }
     364                 :            :         },
     365         [ #  # ]:          0 :         RPCExamples{
     366 [ #  # ][ #  # ]:          0 :             HelpExampleCli("createwallet", "\"testwallet\"")
                 [ #  # ]
     367 [ #  # ][ #  # ]:          0 :             + HelpExampleRpc("createwallet", "\"testwallet\"")
         [ #  # ][ #  # ]
     368 [ #  # ][ #  # ]:          0 :             + HelpExampleCliNamed("createwallet", {{"wallet_name", "descriptors"}, {"avoid_reuse", true}, {"descriptors", true}, {"load_on_startup", true}})
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     369 [ #  # ][ #  # ]:          0 :             + HelpExampleRpcNamed("createwallet", {{"wallet_name", "descriptors"}, {"avoid_reuse", true}, {"descriptors", true}, {"load_on_startup", true}})
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     370                 :            :         },
     371                 :          0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     372                 :            : {
     373                 :          0 :     WalletContext& context = EnsureWalletContext(request.context);
     374                 :          0 :     uint64_t flags = 0;
     375 [ #  # ][ #  # ]:          0 :     if (!request.params[1].isNull() && request.params[1].get_bool()) {
     376                 :          0 :         flags |= WALLET_FLAG_DISABLE_PRIVATE_KEYS;
     377                 :          0 :     }
     378                 :            : 
     379 [ #  # ][ #  # ]:          0 :     if (!request.params[2].isNull() && request.params[2].get_bool()) {
     380                 :          0 :         flags |= WALLET_FLAG_BLANK_WALLET;
     381                 :          0 :     }
     382                 :          0 :     SecureString passphrase;
     383         [ #  # ]:          0 :     passphrase.reserve(100);
     384                 :          0 :     std::vector<bilingual_str> warnings;
     385 [ #  # ][ #  # ]:          0 :     if (!request.params[3].isNull()) {
                 [ #  # ]
     386 [ #  # ][ #  # ]:          0 :         passphrase = std::string_view{request.params[3].get_str()};
                 [ #  # ]
     387         [ #  # ]:          0 :         if (passphrase.empty()) {
     388                 :            :             // Empty string means unencrypted
     389 [ #  # ][ #  # ]:          0 :             warnings.emplace_back(Untranslated("Empty string given as passphrase, wallet will not be encrypted."));
                 [ #  # ]
     390                 :          0 :         }
     391                 :          0 :     }
     392                 :            : 
     393 [ #  # ][ #  # ]:          0 :     if (!request.params[4].isNull() && request.params[4].get_bool()) {
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     394                 :          0 :         flags |= WALLET_FLAG_AVOID_REUSE;
     395                 :          0 :     }
     396 [ #  # ][ #  # ]:          0 :     if (self.Arg<bool>(5)) {
     397                 :            : #ifndef USE_SQLITE
     398                 :            :         throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without sqlite support (required for descriptor wallets)");
     399                 :            : #endif
     400                 :          0 :         flags |= WALLET_FLAG_DESCRIPTORS;
     401                 :          0 :     } else {
     402 [ #  # ][ #  # ]:          0 :         if (!context.chain->rpcEnableDeprecated("create_bdb")) {
                 [ #  # ]
     403 [ #  # ][ #  # ]:          0 :             throw JSONRPCError(RPC_WALLET_ERROR, "BDB wallet creation is deprecated and will be removed in a future release."
                 [ #  # ]
     404                 :            :                                                  " In this release it can be re-enabled temporarily with the -deprecatedrpc=create_bdb setting.");
     405                 :            :         }
     406                 :            :     }
     407 [ #  # ][ #  # ]:          0 :     if (!request.params[7].isNull() && request.params[7].get_bool()) {
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     408                 :            : #ifdef ENABLE_EXTERNAL_SIGNER
     409                 :            :         flags |= WALLET_FLAG_EXTERNAL_SIGNER;
     410                 :            : #else
     411 [ #  # ][ #  # ]:          0 :         throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without external signing support (required for external signing)");
                 [ #  # ]
     412                 :            : #endif
     413                 :            :     }
     414                 :            : 
     415                 :            : #ifndef USE_BDB
     416         [ #  # ]:          0 :     if (!(flags & WALLET_FLAG_DESCRIPTORS)) {
     417 [ #  # ][ #  # ]:          0 :         throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without bdb support (required for legacy wallets)");
                 [ #  # ]
     418                 :            :     }
     419                 :            : #endif
     420                 :            : 
     421                 :          0 :     DatabaseOptions options;
     422                 :            :     DatabaseStatus status;
     423         [ #  # ]:          0 :     ReadDatabaseArgs(*context.args, options);
     424                 :          0 :     options.require_create = true;
     425                 :          0 :     options.create_flags = flags;
     426         [ #  # ]:          0 :     options.create_passphrase = passphrase;
     427                 :          0 :     bilingual_str error;
     428 [ #  # ][ #  # ]:          0 :     std::optional<bool> load_on_start = request.params[6].isNull() ? std::nullopt : std::optional<bool>(request.params[6].get_bool());
         [ #  # ][ #  # ]
                 [ #  # ]
     429 [ #  # ][ #  # ]:          0 :     const std::shared_ptr<CWallet> wallet = CreateWallet(context, request.params[0].get_str(), load_on_start, options, status, error, warnings);
                 [ #  # ]
     430         [ #  # ]:          0 :     if (!wallet) {
     431                 :          0 :         RPCErrorCode code = status == DatabaseStatus::FAILED_ENCRYPT ? RPC_WALLET_ENCRYPTION_FAILED : RPC_WALLET_ERROR;
     432         [ #  # ]:          0 :         throw JSONRPCError(code, error.original);
     433                 :            :     }
     434                 :            : 
     435         [ #  # ]:          0 :     UniValue obj(UniValue::VOBJ);
     436 [ #  # ][ #  # ]:          0 :     obj.pushKV("name", wallet->GetName());
         [ #  # ][ #  # ]
     437         [ #  # ]:          0 :     PushWarnings(warnings, obj);
     438                 :            : 
     439                 :          0 :     return obj;
     440         [ #  # ]:          0 : },
     441                 :            :     };
     442                 :          0 : }
     443                 :            : 
     444                 :          0 : static RPCHelpMan unloadwallet()
     445                 :            : {
     446 [ #  # ][ #  # ]:          0 :     return RPCHelpMan{"unloadwallet",
         [ #  # ][ #  # ]
                 [ #  # ]
     447         [ #  # ]:          0 :                 "Unloads the wallet referenced by the request endpoint, otherwise unloads the wallet specified in the argument.\n"
     448                 :            :                 "Specifying the wallet name on a wallet endpoint is invalid.",
     449         [ #  # ]:          0 :                 {
     450 [ #  # ][ #  # ]:          0 :                     {"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."},
         [ #  # ][ #  # ]
     451 [ #  # ][ #  # ]:          0 :                     {"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."},
                 [ #  # ]
     452                 :            :                 },
     453 [ #  # ][ #  # ]:          0 :                 RPCResult{RPCResult::Type::OBJ, "", "", {
         [ #  # ][ #  # ]
                 [ #  # ]
     454 [ #  # ][ #  # ]:          0 :                     {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to unloading the wallet.",
                 [ #  # ]
     455         [ #  # ]:          0 :                     {
     456 [ #  # ][ #  # ]:          0 :                         {RPCResult::Type::STR, "", ""},
                 [ #  # ]
     457                 :            :                     }},
     458                 :            :                 }},
     459         [ #  # ]:          0 :                 RPCExamples{
     460 [ #  # ][ #  # ]:          0 :                     HelpExampleCli("unloadwallet", "wallet_name")
                 [ #  # ]
     461 [ #  # ][ #  # ]:          0 :             + HelpExampleRpc("unloadwallet", "wallet_name")
         [ #  # ][ #  # ]
     462                 :            :                 },
     463                 :          0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     464                 :            : {
     465                 :          0 :     std::string wallet_name;
     466 [ #  # ][ #  # ]:          0 :     if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
     467 [ #  # ][ #  # ]:          0 :         if (!(request.params[0].isNull() || request.params[0].get_str() == wallet_name)) {
         [ #  # ][ #  # ]
                 [ #  # ]
     468 [ #  # ][ #  # ]:          0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "RPC endpoint wallet and wallet_name parameter specify different wallets");
                 [ #  # ]
     469                 :            :         }
     470                 :          0 :     } else {
     471 [ #  # ][ #  # ]:          0 :         wallet_name = request.params[0].get_str();
                 [ #  # ]
     472                 :            :     }
     473                 :            : 
     474         [ #  # ]:          0 :     WalletContext& context = EnsureWalletContext(request.context);
     475         [ #  # ]:          0 :     std::shared_ptr<CWallet> wallet = GetWallet(context, wallet_name);
     476         [ #  # ]:          0 :     if (!wallet) {
     477 [ #  # ][ #  # ]:          0 :         throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
                 [ #  # ]
     478                 :            :     }
     479                 :            : 
     480                 :          0 :     std::vector<bilingual_str> warnings;
     481                 :            :     {
     482         [ #  # ]:          0 :         WalletRescanReserver reserver(*wallet);
     483 [ #  # ][ #  # ]:          0 :         if (!reserver.reserve()) {
     484 [ #  # ][ #  # ]:          0 :             throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
                 [ #  # ]
     485                 :            :         }
     486                 :            : 
     487                 :            :         // Release the "main" shared pointer and prevent further notifications.
     488                 :            :         // Note that any attempt to load the same wallet would fail until the wallet
     489                 :            :         // is destroyed (see CheckUniqueFileid).
     490         [ #  # ]:          0 :         std::optional<bool> load_on_start{self.MaybeArg<bool>(1)};
     491 [ #  # ][ #  # ]:          0 :         if (!RemoveWallet(context, wallet, load_on_start, warnings)) {
     492 [ #  # ][ #  # ]:          0 :             throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded");
                 [ #  # ]
     493                 :            :         }
     494                 :          0 :     }
     495                 :            : 
     496         [ #  # ]:          0 :     UnloadWallet(std::move(wallet));
     497                 :            : 
     498         [ #  # ]:          0 :     UniValue result(UniValue::VOBJ);
     499         [ #  # ]:          0 :     PushWarnings(warnings, result);
     500                 :            : 
     501                 :          0 :     return result;
     502         [ #  # ]:          0 : },
     503                 :            :     };
     504                 :          0 : }
     505                 :            : 
     506                 :          0 : static RPCHelpMan sethdseed()
     507                 :            : {
     508 [ #  # ][ #  # ]:          0 :     return RPCHelpMan{"sethdseed",
                 [ #  # ]
     509                 :            :                 "\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"
     510                 :            :                 "HD will have a new HD seed set so that new keys added to the keypool will be derived from this new seed.\n"
     511 [ #  # ][ #  # ]:          0 :                 "\nNote that you will need to MAKE A NEW BACKUP of your wallet after setting the HD wallet seed." + HELP_REQUIRING_PASSPHRASE +
     512                 :            :                 "Note: This command is only compatible with legacy wallets.\n",
     513         [ #  # ]:          0 :                 {
     514 [ #  # ][ #  # ]:          0 :                     {"newkeypool", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether to flush old unused addresses, including change addresses, from the keypool and regenerate it.\n"
         [ #  # ][ #  # ]
     515                 :            :                                          "If true, the next address from getnewaddress and change address from getrawchangeaddress will be from this new seed.\n"
     516                 :            :                                          "If false, addresses (including change addresses if the wallet already had HD Chain Split enabled) from the existing\n"
     517                 :            :                                          "keypool will be used until it has been depleted."},
     518 [ #  # ][ #  # ]:          0 :                     {"seed", RPCArg::Type::STR, RPCArg::DefaultHint{"random seed"}, "The WIF private key to use as the new HD seed.\n"
         [ #  # ][ #  # ]
     519                 :            :                                          "The seed value can be retrieved using the dumpwallet command. It is the private key marked hdseed=1"},
     520                 :            :                 },
     521 [ #  # ][ #  # ]:          0 :                 RPCResult{RPCResult::Type::NONE, "", ""},
         [ #  # ][ #  # ]
     522         [ #  # ]:          0 :                 RPCExamples{
     523 [ #  # ][ #  # ]:          0 :                     HelpExampleCli("sethdseed", "")
                 [ #  # ]
     524 [ #  # ][ #  # ]:          0 :             + HelpExampleCli("sethdseed", "false")
         [ #  # ][ #  # ]
     525 [ #  # ][ #  # ]:          0 :             + HelpExampleCli("sethdseed", "true \"wifkey\"")
         [ #  # ][ #  # ]
     526 [ #  # ][ #  # ]:          0 :             + HelpExampleRpc("sethdseed", "true, \"wifkey\"")
         [ #  # ][ #  # ]
     527                 :            :                 },
     528                 :          0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     529                 :            : {
     530                 :          0 :     std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
     531 [ #  # ][ #  # ]:          0 :     if (!pwallet) return UniValue::VNULL;
     532                 :            : 
     533         [ #  # ]:          0 :     LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet, true);
     534                 :            : 
     535 [ #  # ][ #  # ]:          0 :     if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
     536 [ #  # ][ #  # ]:          0 :         throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed to a wallet with private keys disabled");
                 [ #  # ]
     537                 :            :     }
     538                 :            : 
     539 [ #  # ][ #  # ]:          0 :     LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
     540                 :            : 
     541                 :            :     // Do not do anything to non-HD wallets
     542 [ #  # ][ #  # ]:          0 :     if (!pwallet->CanSupportFeature(FEATURE_HD)) {
     543 [ #  # ][ #  # ]:          0 :         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");
                 [ #  # ]
     544                 :            :     }
     545                 :            : 
     546         [ #  # ]:          0 :     EnsureWalletIsUnlocked(*pwallet);
     547                 :            : 
     548                 :          0 :     bool flush_key_pool = true;
     549 [ #  # ][ #  # ]:          0 :     if (!request.params[0].isNull()) {
     550 [ #  # ][ #  # ]:          0 :         flush_key_pool = request.params[0].get_bool();
     551                 :          0 :     }
     552                 :            : 
     553         [ #  # ]:          0 :     CPubKey master_pub_key;
     554 [ #  # ][ #  # ]:          0 :     if (request.params[1].isNull()) {
     555         [ #  # ]:          0 :         master_pub_key = spk_man.GenerateNewSeed();
     556                 :          0 :     } else {
     557 [ #  # ][ #  # ]:          0 :         CKey key = DecodeSecret(request.params[1].get_str());
                 [ #  # ]
     558 [ #  # ][ #  # ]:          0 :         if (!key.IsValid()) {
     559 [ #  # ][ #  # ]:          0 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
                 [ #  # ]
     560                 :            :         }
     561                 :            : 
     562 [ #  # ][ #  # ]:          0 :         if (HaveKey(spk_man, key)) {
     563 [ #  # ][ #  # ]:          0 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Already have this key (either as an HD seed or as a loose private key)");
                 [ #  # ]
     564                 :            :         }
     565                 :            : 
     566         [ #  # ]:          0 :         master_pub_key = spk_man.DeriveNewSeed(key);
     567                 :          0 :     }
     568                 :            : 
     569         [ #  # ]:          0 :     spk_man.SetHDSeed(master_pub_key);
     570 [ #  # ][ #  # ]:          0 :     if (flush_key_pool) spk_man.NewKeyPool();
     571                 :            : 
     572         [ #  # ]:          0 :     return UniValue::VNULL;
     573                 :          0 : },
     574                 :            :     };
     575                 :          0 : }
     576                 :            : 
     577                 :          0 : static RPCHelpMan upgradewallet()
     578                 :            : {
     579 [ #  # ][ #  # ]:          0 :     return RPCHelpMan{"upgradewallet",
         [ #  # ][ #  # ]
     580         [ #  # ]:          0 :         "\nUpgrade the wallet. Upgrades to the latest version if no version number is specified.\n"
     581                 :            :         "New keys may be generated and a new wallet backup will need to be made.",
     582         [ #  # ]:          0 :         {
     583 [ #  # ][ #  # ]:          0 :             {"version", RPCArg::Type::NUM, RPCArg::Default{int{FEATURE_LATEST}}, "The version number to upgrade to. Default is the latest wallet version."}
         [ #  # ][ #  # ]
     584                 :            :         },
     585 [ #  # ][ #  # ]:          0 :         RPCResult{
     586 [ #  # ][ #  # ]:          0 :             RPCResult::Type::OBJ, "", "",
     587         [ #  # ]:          0 :             {
     588 [ #  # ][ #  # ]:          0 :                 {RPCResult::Type::STR, "wallet_name", "Name of wallet this operation was performed on"},
                 [ #  # ]
     589 [ #  # ][ #  # ]:          0 :                 {RPCResult::Type::NUM, "previous_version", "Version of wallet before this operation"},
                 [ #  # ]
     590 [ #  # ][ #  # ]:          0 :                 {RPCResult::Type::NUM, "current_version", "Version of wallet after this operation"},
                 [ #  # ]
     591 [ #  # ][ #  # ]:          0 :                 {RPCResult::Type::STR, "result", /*optional=*/true, "Description of result, if no error"},
                 [ #  # ]
     592 [ #  # ][ #  # ]:          0 :                 {RPCResult::Type::STR, "error", /*optional=*/true, "Error message (if there is one)"}
                 [ #  # ]
     593                 :            :             },
     594                 :            :         },
     595         [ #  # ]:          0 :         RPCExamples{
     596 [ #  # ][ #  # ]:          0 :             HelpExampleCli("upgradewallet", "169900")
                 [ #  # ]
     597 [ #  # ][ #  # ]:          0 :             + HelpExampleRpc("upgradewallet", "169900")
         [ #  # ][ #  # ]
     598                 :            :         },
     599                 :          0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     600                 :            : {
     601                 :          0 :     std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
     602 [ #  # ][ #  # ]:          0 :     if (!pwallet) return UniValue::VNULL;
     603                 :            : 
     604         [ #  # ]:          0 :     EnsureWalletIsUnlocked(*pwallet);
     605                 :            : 
     606                 :          0 :     int version = 0;
     607 [ #  # ][ #  # ]:          0 :     if (!request.params[0].isNull()) {
     608 [ #  # ][ #  # ]:          0 :         version = request.params[0].getInt<int>();
     609                 :          0 :     }
     610                 :          0 :     bilingual_str error;
     611         [ #  # ]:          0 :     const int previous_version{pwallet->GetVersion()};
     612         [ #  # ]:          0 :     const bool wallet_upgraded{pwallet->UpgradeWallet(version, error)};
     613         [ #  # ]:          0 :     const int current_version{pwallet->GetVersion()};
     614                 :          0 :     std::string result;
     615                 :            : 
     616         [ #  # ]:          0 :     if (wallet_upgraded) {
     617         [ #  # ]:          0 :         if (previous_version == current_version) {
     618         [ #  # ]:          0 :             result = "Already at latest version. Wallet version unchanged.";
     619                 :          0 :         } else {
     620         [ #  # ]:          0 :             result = strprintf("Wallet upgraded successfully from version %i to version %i.", previous_version, current_version);
     621                 :            :         }
     622                 :          0 :     }
     623                 :            : 
     624         [ #  # ]:          0 :     UniValue obj(UniValue::VOBJ);
     625 [ #  # ][ #  # ]:          0 :     obj.pushKV("wallet_name", pwallet->GetName());
                 [ #  # ]
     626 [ #  # ][ #  # ]:          0 :     obj.pushKV("previous_version", previous_version);
                 [ #  # ]
     627 [ #  # ][ #  # ]:          0 :     obj.pushKV("current_version", current_version);
                 [ #  # ]
     628         [ #  # ]:          0 :     if (!result.empty()) {
     629 [ #  # ][ #  # ]:          0 :         obj.pushKV("result", result);
                 [ #  # ]
     630                 :          0 :     } else {
     631 [ #  # ][ #  # ]:          0 :         CHECK_NONFATAL(!error.empty());
     632 [ #  # ][ #  # ]:          0 :         obj.pushKV("error", error.original);
                 [ #  # ]
     633                 :            :     }
     634                 :          0 :     return obj;
     635         [ #  # ]:          0 : },
     636                 :            :     };
     637                 :          0 : }
     638                 :            : 
     639                 :          0 : RPCHelpMan simulaterawtransaction()
     640                 :            : {
     641 [ #  # ][ #  # ]:          0 :     return RPCHelpMan{"simulaterawtransaction",
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     642         [ #  # ]:          0 :         "\nCalculate the balance change resulting in the signing and broadcasting of the given transaction(s).\n",
     643         [ #  # ]:          0 :         {
     644 [ #  # ][ #  # ]:          0 :             {"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "An array of hex strings of raw transactions.\n",
                 [ #  # ]
     645         [ #  # ]:          0 :                 {
     646 [ #  # ][ #  # ]:          0 :                     {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
                 [ #  # ]
     647                 :            :                 },
     648                 :            :             },
     649 [ #  # ][ #  # ]:          0 :             {"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
                 [ #  # ]
     650         [ #  # ]:          0 :                 {
     651 [ #  # ][ #  # ]:          0 :                     {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses (see RPC importaddress)"},
         [ #  # ][ #  # ]
     652                 :            :                 },
     653                 :            :             },
     654                 :            :         },
     655 [ #  # ][ #  # ]:          0 :         RPCResult{
     656 [ #  # ][ #  # ]:          0 :             RPCResult::Type::OBJ, "", "",
     657         [ #  # ]:          0 :             {
     658 [ #  # ][ #  # ]:          0 :                 {RPCResult::Type::STR_AMOUNT, "balance_change", "The wallet balance change (negative means decrease)."},
                 [ #  # ]
     659                 :            :             }
     660                 :            :         },
     661         [ #  # ]:          0 :         RPCExamples{
     662 [ #  # ][ #  # ]:          0 :             HelpExampleCli("simulaterawtransaction", "[\"myhex\"]")
                 [ #  # ]
     663 [ #  # ][ #  # ]:          0 :             + HelpExampleRpc("simulaterawtransaction", "[\"myhex\"]")
         [ #  # ][ #  # ]
     664                 :            :         },
     665                 :          0 :     [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     666                 :            : {
     667                 :          0 :     const std::shared_ptr<const CWallet> rpc_wallet = GetWalletForJSONRPCRequest(request);
     668 [ #  # ][ #  # ]:          0 :     if (!rpc_wallet) return UniValue::VNULL;
     669                 :          0 :     const CWallet& wallet = *rpc_wallet;
     670                 :            : 
     671         [ #  # ]:          0 :     LOCK(wallet.cs_wallet);
     672                 :            : 
     673         [ #  # ]:          0 :     UniValue include_watchonly(UniValue::VNULL);
     674 [ #  # ][ #  # ]:          0 :     if (request.params[1].isObject()) {
                 [ #  # ]
     675 [ #  # ][ #  # ]:          0 :         UniValue options = request.params[1];
     676         [ #  # ]:          0 :         RPCTypeCheckObj(options,
     677         [ #  # ]:          0 :             {
     678 [ #  # ][ #  # ]:          0 :                 {"include_watchonly", UniValueType(UniValue::VBOOL)},
     679                 :            :             },
     680                 :            :             true, true);
     681                 :            : 
     682 [ #  # ][ #  # ]:          0 :         include_watchonly = options["include_watchonly"];
                 [ #  # ]
     683                 :          0 :     }
     684                 :            : 
     685                 :          0 :     isminefilter filter = ISMINE_SPENDABLE;
     686 [ #  # ][ #  # ]:          0 :     if (ParseIncludeWatchonly(include_watchonly, wallet)) {
     687                 :          0 :         filter |= ISMINE_WATCH_ONLY;
     688                 :          0 :     }
     689                 :            : 
     690 [ #  # ][ #  # ]:          0 :     const auto& txs = request.params[0].get_array();
     691                 :          0 :     CAmount changes{0};
     692                 :          0 :     std::map<COutPoint, CAmount> new_utxos; // UTXO:s that were made available in transaction array
     693                 :          0 :     std::set<COutPoint> spent;
     694                 :            : 
     695 [ #  # ][ #  # ]:          0 :     for (size_t i = 0; i < txs.size(); ++i) {
     696         [ #  # ]:          0 :         CMutableTransaction mtx;
     697 [ #  # ][ #  # ]:          0 :         if (!DecodeHexTx(mtx, txs[i].get_str(), /* try_no_witness */ true, /* try_witness */ true)) {
         [ #  # ][ #  # ]
     698 [ #  # ][ #  # ]:          0 :             throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Transaction hex string decoding failure.");
                 [ #  # ]
     699                 :            :         }
     700                 :            : 
     701                 :            :         // Fetch previous transactions (inputs)
     702                 :          0 :         std::map<COutPoint, Coin> coins;
     703         [ #  # ]:          0 :         for (const CTxIn& txin : mtx.vin) {
     704         [ #  # ]:          0 :             coins[txin.prevout]; // Create empty map entry keyed by prevout.
     705                 :            :         }
     706 [ #  # ][ #  # ]:          0 :         wallet.chain().findCoins(coins);
     707                 :            : 
     708                 :            :         // Fetch debit; we are *spending* these; if the transaction is signed and
     709                 :            :         // broadcast, we will lose everything in these
     710         [ #  # ]:          0 :         for (const auto& txin : mtx.vin) {
     711                 :          0 :             const auto& outpoint = txin.prevout;
     712 [ #  # ][ #  # ]:          0 :             if (spent.count(outpoint)) {
     713 [ #  # ][ #  # ]:          0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction(s) are spending the same output more than once");
                 [ #  # ]
     714                 :            :             }
     715 [ #  # ][ #  # ]:          0 :             if (new_utxos.count(outpoint)) {
     716         [ #  # ]:          0 :                 changes -= new_utxos.at(outpoint);
     717         [ #  # ]:          0 :                 new_utxos.erase(outpoint);
     718                 :          0 :             } else {
     719 [ #  # ][ #  # ]:          0 :                 if (coins.at(outpoint).IsSpent()) {
                 [ #  # ]
     720 [ #  # ][ #  # ]:          0 :                     throw JSONRPCError(RPC_INVALID_PARAMETER, "One or more transaction inputs are missing or have been spent already");
                 [ #  # ]
     721                 :            :                 }
     722         [ #  # ]:          0 :                 changes -= wallet.GetDebit(txin, filter);
     723                 :            :             }
     724         [ #  # ]:          0 :             spent.insert(outpoint);
     725                 :            :         }
     726                 :            : 
     727                 :            :         // Iterate over outputs; we are *receiving* these, if the wallet considers
     728                 :            :         // them "mine"; if the transaction is signed and broadcast, we will receive
     729                 :            :         // everything in these
     730                 :            :         // Also populate new_utxos in case these are spent in later transactions
     731                 :            : 
     732         [ #  # ]:          0 :         const auto& hash = mtx.GetHash();
     733         [ #  # ]:          0 :         for (size_t i = 0; i < mtx.vout.size(); ++i) {
     734                 :          0 :             const auto& txout = mtx.vout[i];
     735         [ #  # ]:          0 :             bool is_mine = 0 < (wallet.IsMine(txout) & filter);
     736 [ #  # ][ #  # ]:          0 :             changes += new_utxos[COutPoint(hash, i)] = is_mine ? txout.nValue : 0;
                 [ #  # ]
     737                 :          0 :         }
     738                 :          0 :     }
     739                 :            : 
     740         [ #  # ]:          0 :     UniValue result(UniValue::VOBJ);
     741 [ #  # ][ #  # ]:          0 :     result.pushKV("balance_change", ValueFromAmount(changes));
                 [ #  # ]
     742                 :            : 
     743                 :          0 :     return result;
     744         [ #  # ]:          0 : }
     745                 :            :     };
     746                 :          0 : }
     747                 :            : 
     748                 :          0 : static RPCHelpMan migratewallet()
     749                 :            : {
     750 [ #  # ][ #  # ]:          0 :     return RPCHelpMan{"migratewallet",
         [ #  # ][ #  # ]
     751         [ #  # ]:          0 :         "EXPERIMENTAL warning: This call may not work as expected and may be changed in future releases\n"
     752                 :            :         "\nMigrate the wallet to a descriptor wallet.\n"
     753                 :            :         "A new wallet backup will need to be made.\n"
     754                 :            :         "\nThe migration process will create a backup of the wallet before migrating. This backup\n"
     755                 :            :         "file will be named <wallet name>-<timestamp>.legacy.bak and can be found in the directory\n"
     756                 :            :         "for this wallet. In the event of an incorrect migration, the backup can be restored using restorewallet."
     757                 :            :         "\nEncrypted wallets must have the passphrase provided as an argument to this call.",
     758         [ #  # ]:          0 :         {
     759 [ #  # ][ #  # ]:          0 :             {"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."},
         [ #  # ][ #  # ]
     760 [ #  # ][ #  # ]:          0 :             {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "The wallet passphrase"},
                 [ #  # ]
     761                 :            :         },
     762 [ #  # ][ #  # ]:          0 :         RPCResult{
     763 [ #  # ][ #  # ]:          0 :             RPCResult::Type::OBJ, "", "",
     764         [ #  # ]:          0 :             {
     765 [ #  # ][ #  # ]:          0 :                 {RPCResult::Type::STR, "wallet_name", "The name of the primary migrated wallet"},
                 [ #  # ]
     766 [ #  # ][ #  # ]:          0 :                 {RPCResult::Type::STR, "watchonly_name", /*optional=*/true, "The name of the migrated wallet containing the watchonly scripts"},
                 [ #  # ]
     767 [ #  # ][ #  # ]:          0 :                 {RPCResult::Type::STR, "solvables_name", /*optional=*/true, "The name of the migrated wallet containing solvable but not watched scripts"},
                 [ #  # ]
     768 [ #  # ][ #  # ]:          0 :                 {RPCResult::Type::STR, "backup_path", "The location of the backup of the original wallet"},
                 [ #  # ]
     769                 :            :             }
     770                 :            :         },
     771         [ #  # ]:          0 :         RPCExamples{
     772 [ #  # ][ #  # ]:          0 :             HelpExampleCli("migratewallet", "")
                 [ #  # ]
     773 [ #  # ][ #  # ]:          0 :             + HelpExampleRpc("migratewallet", "")
         [ #  # ][ #  # ]
     774                 :            :         },
     775                 :          0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     776                 :            :         {
     777                 :          0 :             std::string wallet_name;
     778 [ #  # ][ #  # ]:          0 :             if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
     779 [ #  # ][ #  # ]:          0 :                 if (!(request.params[0].isNull() || request.params[0].get_str() == wallet_name)) {
         [ #  # ][ #  # ]
                 [ #  # ]
     780 [ #  # ][ #  # ]:          0 :                     throw JSONRPCError(RPC_INVALID_PARAMETER, "RPC endpoint wallet and wallet_name parameter specify different wallets");
                 [ #  # ]
     781                 :            :                 }
     782                 :          0 :             } else {
     783 [ #  # ][ #  # ]:          0 :                 if (request.params[0].isNull()) {
     784 [ #  # ][ #  # ]:          0 :                     throw JSONRPCError(RPC_INVALID_PARAMETER, "Either RPC endpoint wallet or wallet_name parameter must be provided");
                 [ #  # ]
     785                 :            :                 }
     786 [ #  # ][ #  # ]:          0 :                 wallet_name = request.params[0].get_str();
                 [ #  # ]
     787                 :            :             }
     788                 :            : 
     789                 :          0 :             SecureString wallet_pass;
     790         [ #  # ]:          0 :             wallet_pass.reserve(100);
     791 [ #  # ][ #  # ]:          0 :             if (!request.params[1].isNull()) {
     792 [ #  # ][ #  # ]:          0 :                 wallet_pass = std::string_view{request.params[1].get_str()};
                 [ #  # ]
     793                 :          0 :             }
     794                 :            : 
     795         [ #  # ]:          0 :             WalletContext& context = EnsureWalletContext(request.context);
     796         [ #  # ]:          0 :             util::Result<MigrationResult> res = MigrateLegacyToDescriptor(wallet_name, wallet_pass, context);
     797         [ #  # ]:          0 :             if (!res) {
     798 [ #  # ][ #  # ]:          0 :                 throw JSONRPCError(RPC_WALLET_ERROR, util::ErrorString(res).original);
                 [ #  # ]
     799                 :            :             }
     800                 :            : 
     801         [ #  # ]:          0 :             UniValue r{UniValue::VOBJ};
     802 [ #  # ][ #  # ]:          0 :             r.pushKV("wallet_name", res->wallet_name);
         [ #  # ][ #  # ]
     803 [ #  # ][ #  # ]:          0 :             if (res->watchonly_wallet) {
     804 [ #  # ][ #  # ]:          0 :                 r.pushKV("watchonly_name", res->watchonly_wallet->GetName());
         [ #  # ][ #  # ]
     805                 :          0 :             }
     806 [ #  # ][ #  # ]:          0 :             if (res->solvables_wallet) {
     807 [ #  # ][ #  # ]:          0 :                 r.pushKV("solvables_name", res->solvables_wallet->GetName());
         [ #  # ][ #  # ]
     808                 :          0 :             }
     809 [ #  # ][ #  # ]:          0 :             r.pushKV("backup_path", res->backup_path.utf8string());
         [ #  # ][ #  # ]
                 [ #  # ]
     810                 :            : 
     811                 :          0 :             return r;
     812         [ #  # ]:          0 :         },
     813                 :            :     };
     814                 :          0 : }
     815                 :            : 
     816                 :            : // addresses
     817                 :            : RPCHelpMan getaddressinfo();
     818                 :            : RPCHelpMan getnewaddress();
     819                 :            : RPCHelpMan getrawchangeaddress();
     820                 :            : RPCHelpMan setlabel();
     821                 :            : RPCHelpMan listaddressgroupings();
     822                 :            : RPCHelpMan addmultisigaddress();
     823                 :            : RPCHelpMan keypoolrefill();
     824                 :            : RPCHelpMan newkeypool();
     825                 :            : RPCHelpMan getaddressesbylabel();
     826                 :            : RPCHelpMan listlabels();
     827                 :            : #ifdef ENABLE_EXTERNAL_SIGNER
     828                 :            : RPCHelpMan walletdisplayaddress();
     829                 :            : #endif // ENABLE_EXTERNAL_SIGNER
     830                 :            : 
     831                 :            : // backup
     832                 :            : RPCHelpMan dumpprivkey();
     833                 :            : RPCHelpMan importprivkey();
     834                 :            : RPCHelpMan importaddress();
     835                 :            : RPCHelpMan importpubkey();
     836                 :            : RPCHelpMan dumpwallet();
     837                 :            : RPCHelpMan importwallet();
     838                 :            : RPCHelpMan importprunedfunds();
     839                 :            : RPCHelpMan removeprunedfunds();
     840                 :            : RPCHelpMan importmulti();
     841                 :            : RPCHelpMan importdescriptors();
     842                 :            : RPCHelpMan listdescriptors();
     843                 :            : RPCHelpMan backupwallet();
     844                 :            : RPCHelpMan restorewallet();
     845                 :            : 
     846                 :            : // coins
     847                 :            : RPCHelpMan getreceivedbyaddress();
     848                 :            : RPCHelpMan getreceivedbylabel();
     849                 :            : RPCHelpMan getbalance();
     850                 :            : RPCHelpMan getunconfirmedbalance();
     851                 :            : RPCHelpMan lockunspent();
     852                 :            : RPCHelpMan listlockunspent();
     853                 :            : RPCHelpMan getbalances();
     854                 :            : RPCHelpMan listunspent();
     855                 :            : 
     856                 :            : // encryption
     857                 :            : RPCHelpMan walletpassphrase();
     858                 :            : RPCHelpMan walletpassphrasechange();
     859                 :            : RPCHelpMan walletlock();
     860                 :            : RPCHelpMan encryptwallet();
     861                 :            : 
     862                 :            : // spend
     863                 :            : RPCHelpMan sendtoaddress();
     864                 :            : RPCHelpMan sendmany();
     865                 :            : RPCHelpMan settxfee();
     866                 :            : RPCHelpMan fundrawtransaction();
     867                 :            : RPCHelpMan bumpfee();
     868                 :            : RPCHelpMan psbtbumpfee();
     869                 :            : RPCHelpMan send();
     870                 :            : RPCHelpMan sendall();
     871                 :            : RPCHelpMan walletprocesspsbt();
     872                 :            : RPCHelpMan walletcreatefundedpsbt();
     873                 :            : RPCHelpMan signrawtransactionwithwallet();
     874                 :            : 
     875                 :            : // signmessage
     876                 :            : RPCHelpMan signmessage();
     877                 :            : 
     878                 :            : // transactions
     879                 :            : RPCHelpMan listreceivedbyaddress();
     880                 :            : RPCHelpMan listreceivedbylabel();
     881                 :            : RPCHelpMan listtransactions();
     882                 :            : RPCHelpMan listsinceblock();
     883                 :            : RPCHelpMan gettransaction();
     884                 :            : RPCHelpMan abandontransaction();
     885                 :            : RPCHelpMan rescanblockchain();
     886                 :            : RPCHelpMan abortrescan();
     887                 :            : 
     888                 :          0 : Span<const CRPCCommand> GetWalletRPCCommands()
     889                 :            : {
     890 [ #  # ][ #  # ]:          0 :     static const CRPCCommand commands[]{
                 [ #  # ]
     891 [ #  # ][ #  # ]:          0 :         {"rawtransactions", &fundrawtransaction},
     892 [ #  # ][ #  # ]:          0 :         {"wallet", &abandontransaction},
     893 [ #  # ][ #  # ]:          0 :         {"wallet", &abortrescan},
     894 [ #  # ][ #  # ]:          0 :         {"wallet", &addmultisigaddress},
     895 [ #  # ][ #  # ]:          0 :         {"wallet", &backupwallet},
     896 [ #  # ][ #  # ]:          0 :         {"wallet", &bumpfee},
     897 [ #  # ][ #  # ]:          0 :         {"wallet", &psbtbumpfee},
     898 [ #  # ][ #  # ]:          0 :         {"wallet", &createwallet},
     899 [ #  # ][ #  # ]:          0 :         {"wallet", &restorewallet},
     900 [ #  # ][ #  # ]:          0 :         {"wallet", &dumpprivkey},
     901 [ #  # ][ #  # ]:          0 :         {"wallet", &dumpwallet},
     902 [ #  # ][ #  # ]:          0 :         {"wallet", &encryptwallet},
     903 [ #  # ][ #  # ]:          0 :         {"wallet", &getaddressesbylabel},
     904 [ #  # ][ #  # ]:          0 :         {"wallet", &getaddressinfo},
     905 [ #  # ][ #  # ]:          0 :         {"wallet", &getbalance},
     906 [ #  # ][ #  # ]:          0 :         {"wallet", &getnewaddress},
     907 [ #  # ][ #  # ]:          0 :         {"wallet", &getrawchangeaddress},
     908 [ #  # ][ #  # ]:          0 :         {"wallet", &getreceivedbyaddress},
     909 [ #  # ][ #  # ]:          0 :         {"wallet", &getreceivedbylabel},
     910 [ #  # ][ #  # ]:          0 :         {"wallet", &gettransaction},
     911 [ #  # ][ #  # ]:          0 :         {"wallet", &getunconfirmedbalance},
     912 [ #  # ][ #  # ]:          0 :         {"wallet", &getbalances},
     913 [ #  # ][ #  # ]:          0 :         {"wallet", &getwalletinfo},
     914 [ #  # ][ #  # ]:          0 :         {"wallet", &importaddress},
     915 [ #  # ][ #  # ]:          0 :         {"wallet", &importdescriptors},
     916 [ #  # ][ #  # ]:          0 :         {"wallet", &importmulti},
     917 [ #  # ][ #  # ]:          0 :         {"wallet", &importprivkey},
     918 [ #  # ][ #  # ]:          0 :         {"wallet", &importprunedfunds},
     919 [ #  # ][ #  # ]:          0 :         {"wallet", &importpubkey},
     920 [ #  # ][ #  # ]:          0 :         {"wallet", &importwallet},
     921 [ #  # ][ #  # ]:          0 :         {"wallet", &keypoolrefill},
     922 [ #  # ][ #  # ]:          0 :         {"wallet", &listaddressgroupings},
     923 [ #  # ][ #  # ]:          0 :         {"wallet", &listdescriptors},
     924 [ #  # ][ #  # ]:          0 :         {"wallet", &listlabels},
     925 [ #  # ][ #  # ]:          0 :         {"wallet", &listlockunspent},
     926 [ #  # ][ #  # ]:          0 :         {"wallet", &listreceivedbyaddress},
     927 [ #  # ][ #  # ]:          0 :         {"wallet", &listreceivedbylabel},
     928 [ #  # ][ #  # ]:          0 :         {"wallet", &listsinceblock},
     929 [ #  # ][ #  # ]:          0 :         {"wallet", &listtransactions},
     930 [ #  # ][ #  # ]:          0 :         {"wallet", &listunspent},
     931 [ #  # ][ #  # ]:          0 :         {"wallet", &listwalletdir},
     932 [ #  # ][ #  # ]:          0 :         {"wallet", &listwallets},
     933 [ #  # ][ #  # ]:          0 :         {"wallet", &loadwallet},
     934 [ #  # ][ #  # ]:          0 :         {"wallet", &lockunspent},
     935 [ #  # ][ #  # ]:          0 :         {"wallet", &migratewallet},
     936 [ #  # ][ #  # ]:          0 :         {"wallet", &newkeypool},
     937 [ #  # ][ #  # ]:          0 :         {"wallet", &removeprunedfunds},
     938 [ #  # ][ #  # ]:          0 :         {"wallet", &rescanblockchain},
     939 [ #  # ][ #  # ]:          0 :         {"wallet", &send},
     940 [ #  # ][ #  # ]:          0 :         {"wallet", &sendmany},
     941 [ #  # ][ #  # ]:          0 :         {"wallet", &sendtoaddress},
     942 [ #  # ][ #  # ]:          0 :         {"wallet", &sethdseed},
     943 [ #  # ][ #  # ]:          0 :         {"wallet", &setlabel},
     944 [ #  # ][ #  # ]:          0 :         {"wallet", &settxfee},
     945 [ #  # ][ #  # ]:          0 :         {"wallet", &setwalletflag},
     946 [ #  # ][ #  # ]:          0 :         {"wallet", &signmessage},
     947 [ #  # ][ #  # ]:          0 :         {"wallet", &signrawtransactionwithwallet},
     948 [ #  # ][ #  # ]:          0 :         {"wallet", &simulaterawtransaction},
     949 [ #  # ][ #  # ]:          0 :         {"wallet", &sendall},
     950 [ #  # ][ #  # ]:          0 :         {"wallet", &unloadwallet},
     951 [ #  # ][ #  # ]:          0 :         {"wallet", &upgradewallet},
     952 [ #  # ][ #  # ]:          0 :         {"wallet", &walletcreatefundedpsbt},
     953                 :            : #ifdef ENABLE_EXTERNAL_SIGNER
     954                 :            :         {"wallet", &walletdisplayaddress},
     955                 :            : #endif // ENABLE_EXTERNAL_SIGNER
     956 [ #  # ][ #  # ]:          0 :         {"wallet", &walletlock},
     957 [ #  # ][ #  # ]:          0 :         {"wallet", &walletpassphrase},
     958 [ #  # ][ #  # ]:          0 :         {"wallet", &walletpassphrasechange},
     959 [ #  # ][ #  # ]:          0 :         {"wallet", &walletprocesspsbt},
     960                 :            :     };
     961                 :          0 :     return commands;
     962                 :          0 : }
     963                 :            : } // namespace wallet

Generated by: LCOV version 1.14