LCOV - code coverage report
Current view: top level - src/wallet - wallettool.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 130 173 75.1 %
Date: 2026-06-25 07:23:43 Functions: 7 7 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2016-2021 The Bitcoin Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #if defined(HAVE_CONFIG_H)
       6             : #include <config/bitcoin-config.h>
       7             : #endif
       8             : 
       9             : #include <wallet/wallettool.h>
      10             : 
      11             : #include <fs.h>
      12             : #include <util/translation.h>
      13             : #include <util/system.h>
      14             : #include <wallet/dump.h>
      15             : #include <wallet/salvage.h>
      16             : #include <wallet/wallet.h>
      17             : #include <wallet/walletutil.h>
      18             : 
      19             : namespace wallet {
      20             : namespace WalletTool {
      21             : 
      22             : // The standard wallet deleter function blocks on the validation interface
      23             : // queue, which doesn't exist for the dash-wallet. Define our own
      24             : // deleter here.
      25          18 : static void WalletToolReleaseWallet(CWallet* wallet)
      26             : {
      27          18 :     wallet->WalletLogPrintf("Releasing wallet\n");
      28          18 :     wallet->Close();
      29          18 :     delete wallet;
      30          18 : }
      31             : 
      32             : static const bool DEFAULT_USE_HD_WALLET{true};
      33             : 
      34           4 : static void WalletCreate(CWallet* wallet_instance, uint64_t wallet_creation_flags)
      35             : {
      36           4 :     LOCK(wallet_instance->cs_wallet);
      37           4 :     if (gArgs.GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET)) {
      38           4 :         wallet_instance->SetMinVersion(FEATURE_LATEST);
      39           4 :     } else {
      40           0 :         wallet_instance->SetMinVersion(FEATURE_COMPRPUBKEY);
      41             :     }
      42           4 :     wallet_instance->InitWalletFlags(wallet_creation_flags);
      43             : 
      44           4 :     if (!wallet_instance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
      45             :         // TODO: use here SetupGeneration instead, such as: spk_man->SetupGeneration(false);
      46             :         // SetupGeneration is not backported yet
      47           2 :         wallet_instance->SetupLegacyScriptPubKeyMan();
      48           2 :         auto spk_man = wallet_instance->GetOrCreateLegacyScriptPubKeyMan();
      49           2 :         if (gArgs.GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET)) {
      50           2 :             spk_man->GenerateNewHDChain(/*secureMnemonic=*/"", /*secureMnemonicPassphrase=*/"");
      51           2 :         }
      52           2 :     } else {
      53           2 :         wallet_instance->SetupDescriptorScriptPubKeyMans("", "");
      54             :     }
      55             : 
      56           4 :     tfm::format(std::cout, "Topping up keypool...\n");
      57           4 :     wallet_instance->TopUpKeyPool();
      58           4 : }
      59             : 
      60          26 : static std::shared_ptr<CWallet> MakeWallet(const std::string& name, const fs::path& path, const ArgsManager& args, DatabaseOptions options)
      61             : {
      62             :     DatabaseStatus status;
      63          26 :     bilingual_str error;
      64          26 :     std::unique_ptr<WalletDatabase> database = MakeDatabase(path, options, status, error);
      65          26 :     if (!database) {
      66           8 :         tfm::format(std::cerr, "%s\n", error.original);
      67           8 :         return nullptr;
      68             :     }
      69             : 
      70             :     // dummy chain interface
      71          18 :     std::shared_ptr<CWallet> wallet_instance{new CWallet(/*chain=*/nullptr, /*coinjoin_loader=*/nullptr, name, args, std::move(database)), WalletToolReleaseWallet};
      72             :     DBErrors load_wallet_ret;
      73             :     try {
      74          18 :         load_wallet_ret = wallet_instance->LoadWallet();
      75          18 :     } catch (const std::runtime_error&) {
      76           0 :         tfm::format(std::cerr, "Error loading %s. Is wallet being used by another process?\n", name);
      77           0 :         return nullptr;
      78           0 :     }
      79             : 
      80          18 :     if (load_wallet_ret != DBErrors::LOAD_OK) {
      81           0 :         if (load_wallet_ret == DBErrors::CORRUPT) {
      82           0 :             tfm::format(std::cerr, "Error loading %s: Wallet corrupted", name);
      83           0 :             return nullptr;
      84           0 :         } else if (load_wallet_ret == DBErrors::NONCRITICAL_ERROR) {
      85           0 :             tfm::format(std::cerr, "Error reading %s! All keys read correctly, but transaction data"
      86             :                             " or address book entries might be missing or incorrect.",
      87           0 :                 name);
      88           0 :         } else if (load_wallet_ret == DBErrors::TOO_NEW) {
      89           0 :             tfm::format(std::cerr, "Error loading %s: Wallet requires newer version of %s",
      90           0 :                 name, PACKAGE_NAME);
      91           0 :             return nullptr;
      92           0 :         } else if (load_wallet_ret == DBErrors::NEED_REWRITE) {
      93           0 :             tfm::format(std::cerr, "Wallet needed to be rewritten: restart %s to complete", PACKAGE_NAME);
      94           0 :             return nullptr;
      95             :         } else {
      96           0 :             tfm::format(std::cerr, "Error loading %s", name);
      97           0 :             return nullptr;
      98             :         }
      99           0 :     }
     100             : 
     101          18 :     if (options.require_create) WalletCreate(wallet_instance.get(), options.create_flags);
     102             : 
     103          18 :     return wallet_instance;
     104          26 : }
     105             : 
     106          16 : static void WalletShowInfo(CWallet* wallet_instance)
     107             : {
     108             :     // lock required because of some AssertLockHeld()
     109          16 :     LOCK(wallet_instance->cs_wallet);
     110             : 
     111          16 :     CHDChain hdChainTmp;
     112          16 :     tfm::format(std::cout, "Wallet info\n===========\n");
     113          16 :     tfm::format(std::cout, "Name: %s\n", wallet_instance->GetName());
     114          16 :     tfm::format(std::cout, "Format: %s\n", wallet_instance->GetDatabase().Format());
     115          16 :     tfm::format(std::cout, "Descriptors: %s\n", wallet_instance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS) ? "yes" : "no");
     116          16 :     tfm::format(std::cout, "Encrypted: %s\n", wallet_instance->IsCrypted() ? "yes" : "no");
     117          16 :     tfm::format(std::cout, "HD (hd seed available): %s\n", wallet_instance->IsHDEnabled() ? "yes" : "no");
     118          16 :     tfm::format(std::cout, "Keypool Size: %u\n", wallet_instance->GetKeyPoolSize());
     119          16 :     tfm::format(std::cout, "Transactions: %zu\n", wallet_instance->mapWallet.size());
     120          16 :     tfm::format(std::cout, "Address Book: %zu\n", wallet_instance->m_address_book.size());
     121          16 : }
     122             : 
     123         116 : bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command)
     124             : {
     125         116 :     if (args.IsArgSet("-format") && command != "createfromdump") {
     126           0 :         tfm::format(std::cerr, "The -format option can only be used with the \"createfromdump\" command.\n");
     127           0 :         return false;
     128             :     }
     129         116 :     if (args.IsArgSet("-dumpfile") && command != "dump" && command != "createfromdump") {
     130           0 :         tfm::format(std::cerr, "The -dumpfile option can only be used with the \"dump\" and \"createfromdump\" commands.\n");
     131           0 :         return false;
     132             :     }
     133         116 :     if (args.IsArgSet("-descriptors") && command != "create") {
     134           4 :         tfm::format(std::cerr, "The -descriptors option can only be used with the 'create' command.\n");
     135           4 :         return false;
     136             :     }
     137         112 :     if (args.IsArgSet("-legacy") && command != "create") {
     138           0 :         tfm::format(std::cerr, "The -legacy option can only be used with the 'create' command.\n");
     139           0 :         return false;
     140             :     }
     141         112 :     if (command == "create" && !args.IsArgSet("-wallet")) {
     142           4 :         tfm::format(std::cerr, "Wallet name must be provided when creating a new wallet.\n");
     143           4 :         return false;
     144             :     }
     145         108 :     const std::string name = args.GetArg("-wallet", "");
     146         108 :     const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), fs::PathFromString(name));
     147             : 
     148         108 :     if (command == "create") {
     149           4 :         DatabaseOptions options;
     150           4 :         ReadDatabaseArgs(args, options);
     151           4 :         options.require_create = true;
     152             :         // If -legacy is set, use it. Otherwise default to false.
     153           4 :         bool make_legacy = args.GetBoolArg("-legacy", false);
     154             :         // If neither -legacy nor -descriptors is set, default to true. If -descriptors is set, use its value.
     155           4 :         bool make_descriptors = (!args.IsArgSet("-descriptors") && !args.IsArgSet("-legacy")) || (args.IsArgSet("-descriptors") && args.GetBoolArg("-descriptors", true));
     156           4 :         if (make_legacy && make_descriptors) {
     157           0 :             tfm::format(std::cerr, "Only one of -legacy or -descriptors can be set to true, not both\n");
     158           0 :             return false;
     159             :         }
     160           4 :         if (!make_legacy && !make_descriptors) {
     161           0 :             tfm::format(std::cerr, "One of -legacy or -descriptors must be set to true (or omitted)\n");
     162           0 :             return false;
     163             :         }
     164           4 :         if (make_descriptors) {
     165           2 :             options.create_flags |= WALLET_FLAG_DESCRIPTORS;
     166           2 :             options.require_format = DatabaseFormat::SQLITE;
     167           2 :         }
     168             : 
     169           4 :         const std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, args, options);
     170           4 :         if (wallet_instance) {
     171           4 :             WalletShowInfo(wallet_instance.get());
     172           4 :             wallet_instance->Close();
     173           4 :         }
     174         108 :     } else if (command == "info") {
     175          20 :         DatabaseOptions options;
     176          20 :         ReadDatabaseArgs(args, options);
     177          20 :         options.require_existing = true;
     178          20 :         const std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, args, options);
     179          20 :         if (!wallet_instance) return false;
     180          12 :         WalletShowInfo(wallet_instance.get());
     181          12 :         wallet_instance->Close();
     182         104 :     } else if (command == "salvage") {
     183             : #ifdef USE_BDB
     184           2 :         bilingual_str error;
     185           2 :         std::vector<bilingual_str> warnings;
     186           2 :         bool ret = RecoverDatabaseFile(args, path, error, warnings);
     187           2 :         if (!ret) {
     188           0 :             for (const auto& warning : warnings) {
     189           0 :                 tfm::format(std::cerr, "%s\n", warning.original);
     190             :             }
     191           0 :             if (!error.empty()) {
     192           0 :                 tfm::format(std::cerr, "%s\n", error.original);
     193           0 :             }
     194           0 :         }
     195           2 :         return ret;
     196             : #else
     197             :         tfm::format(std::cerr, "Salvage command is not available as BDB support is not compiled");
     198             :         return false;
     199             : #endif
     200          84 :     } else if (command == "wipetxes") {
     201             : #ifdef USE_BDB
     202           2 :         DatabaseOptions options;
     203           2 :         options.require_existing = true;
     204           2 :         const std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, args, options);
     205           2 :         if (wallet_instance == nullptr) return false;
     206             : 
     207           2 :         std::vector<uint256> vHash;
     208           2 :         std::vector<uint256> vHashOut;
     209             : 
     210           2 :         LOCK(wallet_instance->cs_wallet);
     211             : 
     212           4 :         for (auto& [txid, _] : wallet_instance->mapWallet) {
     213           2 :             vHash.push_back(txid);
     214             :         }
     215             : 
     216           2 :         if (wallet_instance->ZapSelectTx(vHash, vHashOut) != DBErrors::LOAD_OK) {
     217           0 :             tfm::format(std::cerr, "Could not properly delete transactions");
     218           0 :             wallet_instance->Close();
     219           0 :             return false;
     220             :         }
     221             : 
     222           2 :         wallet_instance->Close();
     223           2 :         return vHashOut.size() == vHash.size();
     224             : #else
     225             :         tfm::format(std::cerr, "Wipetxes command is not available as BDB support is not compiled");
     226             :         return false;
     227             : #endif
     228          82 :     } else if (command == "dump") {
     229          24 :         DatabaseOptions options;
     230          24 :         ReadDatabaseArgs(args, options);
     231          24 :         options.require_existing = true;
     232             :         DatabaseStatus status;
     233          24 :         bilingual_str error;
     234          24 :         std::unique_ptr<WalletDatabase> database = MakeDatabase(path, options, status, error);
     235          24 :         if (!database) {
     236           0 :             tfm::format(std::cerr, "%s\n", error.original);
     237           0 :             return false;
     238             :         }
     239             : 
     240          24 :         bool ret = DumpWallet(args, *database, error);
     241          24 :         if (!ret && !error.empty()) {
     242           8 :             tfm::format(std::cerr, "%s\n", error.original);
     243           8 :             return ret;
     244             :         }
     245          16 :         tfm::format(std::cout, "The dumpfile may contain private keys. To ensure the safety of your Bitcoin, do not share the dumpfile.\n");
     246          16 :         return ret;
     247          80 :     } else if (command == "createfromdump") {
     248          56 :         bilingual_str error;
     249          56 :         std::vector<bilingual_str> warnings;
     250          56 :         bool ret = CreateFromDump(args, name, path, error, warnings);
     251          60 :         for (const auto& warning : warnings) {
     252           4 :             tfm::format(std::cout, "%s\n", warning.original);
     253             :         }
     254          56 :         if (!ret && !error.empty()) {
     255          44 :             tfm::format(std::cerr, "%s\n", error.original);
     256          44 :         }
     257          56 :         return ret;
     258          56 :     } else {
     259           0 :         tfm::format(std::cerr, "Invalid command: %s\n", command);
     260           0 :         return false;
     261             :     }
     262             : 
     263          16 :     return true;
     264         116 : }
     265             : } // namespace WalletTool
     266             : } // namespace wallet

Generated by: LCOV version 1.16