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