/ src / bitcoin-wallet.cpp
bitcoin-wallet.cpp
  1  // Copyright (c) 2016-2022 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 <chainparams.h>
 10  #include <chainparamsbase.h>
 11  #include <clientversion.h>
 12  #include <common/args.h>
 13  #include <common/system.h>
 14  #include <common/url.h>
 15  #include <compat/compat.h>
 16  #include <interfaces/init.h>
 17  #include <key.h>
 18  #include <logging.h>
 19  #include <pubkey.h>
 20  #include <tinyformat.h>
 21  #include <util/exception.h>
 22  #include <util/translation.h>
 23  #include <wallet/wallettool.h>
 24  
 25  #include <exception>
 26  #include <functional>
 27  #include <string>
 28  #include <tuple>
 29  
 30  const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
 31  UrlDecodeFn* const URL_DECODE = nullptr;
 32  
 33  static void SetupWalletToolArgs(ArgsManager& argsman)
 34  {
 35      SetupHelpOptions(argsman);
 36      SetupChainParamsBaseOptions(argsman);
 37  
 38      argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
 39      argsman.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
 40      argsman.AddArg("-wallet=<wallet-name>", "Specify wallet name", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::OPTIONS);
 41      argsman.AddArg("-dumpfile=<file name>", "When used with 'dump', writes out the records to this file. When used with 'createfromdump', loads the records into a new wallet.", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS);
 42      argsman.AddArg("-debug=<category>", "Output debugging information (default: 0).", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
 43      argsman.AddArg("-descriptors", "Create descriptors wallet. Only for 'create'", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
 44      argsman.AddArg("-legacy", "Create legacy wallet. Only for 'create'", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
 45      argsman.AddArg("-format=<format>", "The format of the wallet file to create. Either \"bdb\" or \"sqlite\". Only used with 'createfromdump'", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
 46      argsman.AddArg("-printtoconsole", "Send trace/debug info to console (default: 1 when no -debug is true, 0 otherwise).", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
 47  
 48      argsman.AddCommand("info", "Get wallet info");
 49      argsman.AddCommand("create", "Create new wallet file");
 50      argsman.AddCommand("salvage", "Attempt to recover private keys from a corrupt wallet. Warning: 'salvage' is experimental.");
 51      argsman.AddCommand("dump", "Print out all of the wallet key-value records");
 52      argsman.AddCommand("createfromdump", "Create new wallet file from dumped records");
 53  }
 54  
 55  static std::optional<int> WalletAppInit(ArgsManager& args, int argc, char* argv[])
 56  {
 57      SetupWalletToolArgs(args);
 58      std::string error_message;
 59      if (!args.ParseParameters(argc, argv, error_message)) {
 60          tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error_message);
 61          return EXIT_FAILURE;
 62      }
 63      const bool missing_args{argc < 2};
 64      if (missing_args || HelpRequested(args) || args.IsArgSet("-version")) {
 65          std::string strUsage = strprintf("%s bitcoin-wallet version", PACKAGE_NAME) + " " + FormatFullVersion() + "\n";
 66  
 67          if (args.IsArgSet("-version")) {
 68              strUsage += FormatParagraph(LicenseInfo());
 69          } else {
 70              strUsage += "\n"
 71                          "bitcoin-wallet is an offline tool for creating and interacting with " PACKAGE_NAME " wallet files.\n"
 72                          "By default bitcoin-wallet will act on wallets in the default mainnet wallet directory in the datadir.\n"
 73                          "To change the target wallet, use the -datadir, -wallet and -regtest/-signet/-testnet arguments.\n\n"
 74                          "Usage:\n"
 75                          "  bitcoin-wallet [options] <command>\n";
 76              strUsage += "\n" + args.GetHelpMessage();
 77          }
 78          tfm::format(std::cout, "%s", strUsage);
 79          if (missing_args) {
 80              tfm::format(std::cerr, "Error: too few parameters\n");
 81              return EXIT_FAILURE;
 82          }
 83          return EXIT_SUCCESS;
 84      }
 85  
 86      // check for printtoconsole, allow -debug
 87      LogInstance().m_print_to_console = args.GetBoolArg("-printtoconsole", args.GetBoolArg("-debug", false));
 88  
 89      if (!CheckDataDirOption(args)) {
 90          tfm::format(std::cerr, "Error: Specified data directory \"%s\" does not exist.\n", args.GetArg("-datadir", ""));
 91          return EXIT_FAILURE;
 92      }
 93      // Check for chain settings (Params() calls are only valid after this clause)
 94      SelectParams(args.GetChainType());
 95  
 96      return std::nullopt;
 97  }
 98  
 99  MAIN_FUNCTION
100  {
101      ArgsManager& args = gArgs;
102  #ifdef WIN32
103      common::WinCmdLineArgs winArgs;
104      std::tie(argc, argv) = winArgs.get();
105  #endif
106  
107      int exit_status;
108      std::unique_ptr<interfaces::Init> init = interfaces::MakeWalletInit(argc, argv, exit_status);
109      if (!init) {
110          return exit_status;
111      }
112  
113      SetupEnvironment();
114      RandomInit();
115      try {
116          if (const auto maybe_exit{WalletAppInit(args, argc, argv)}) return *maybe_exit;
117      } catch (const std::exception& e) {
118          PrintExceptionContinue(&e, "WalletAppInit()");
119          return EXIT_FAILURE;
120      } catch (...) {
121          PrintExceptionContinue(nullptr, "WalletAppInit()");
122          return EXIT_FAILURE;
123      }
124  
125      const auto command = args.GetCommand();
126      if (!command) {
127          tfm::format(std::cerr, "No method provided. Run `bitcoin-wallet -help` for valid methods.\n");
128          return EXIT_FAILURE;
129      }
130      if (command->args.size() != 0) {
131          tfm::format(std::cerr, "Error: Additional arguments provided (%s). Methods do not take arguments. Please refer to `-help`.\n", Join(command->args, ", "));
132          return EXIT_FAILURE;
133      }
134  
135      ECC_Start();
136      if (!wallet::WalletTool::ExecuteWalletToolFunc(args, command->command)) {
137          return EXIT_FAILURE;
138      }
139      ECC_Stop();
140      return EXIT_SUCCESS;
141  }