Line data Source code
1 : // Copyright (c) 2009-2010 Satoshi Nakamoto
2 : // Copyright (c) 2009-2017 The Bitcoin Core developers
3 : // Copyright (c) 2021 The PIVX Core developers
4 : // Distributed under the MIT software license, see the accompanying
5 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 :
7 : #include "wallet/init.h"
8 :
9 : #include "guiinterfaceutil.h"
10 : #include "net.h"
11 : #include "util/system.h"
12 : #include "utilmoneystr.h"
13 : #include "validation.h"
14 : #include "wallet/wallet.h"
15 : #include "wallet/walletutil.h"
16 :
17 1 : std::string GetWalletHelpString(bool showDebug)
18 : {
19 1 : std::string strUsage = HelpMessageGroup("Wallet options:");
20 4 : strUsage += HelpMessageOpt("-createwalletbackups=<n>", strprintf("Number of automatic wallet backups (default: %d)", DEFAULT_CREATEWALLETBACKUPS));
21 3 : strUsage += HelpMessageOpt("-disablewallet", strprintf("Do not load the wallet and disable wallet RPC calls (default: %u)", DEFAULT_DISABLE_WALLET));
22 3 : strUsage += HelpMessageOpt("-keypool=<n>", strprintf("Set key pool size to <n> (default: %u)", DEFAULT_KEYPOOL_SIZE));
23 3 : strUsage += HelpMessageOpt("-legacywallet", "On first run, create a legacy wallet instead of a HD wallet");
24 4 : strUsage += HelpMessageOpt("-maxtxfee=<amt>", strprintf("Maximum total fees to use in a single wallet transaction, setting too low may abort large transactions (default: %s)", FormatMoney(maxTxFee)));
25 4 : strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf("Fees (in %s/Kb) smaller than this are considered zero fee for transaction creation (default: %s)", CURRENCY_UNIT, FormatMoney(CWallet::minTxFee.GetFeePerK())));
26 4 : strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf("Fee (in %s/kB) to add to transactions you send (default: %s)", CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK())));
27 3 : strUsage += HelpMessageOpt("-rescan", "Rescan the block chain for missing wallet transactions on startup");
28 3 : strUsage += HelpMessageOpt("-salvagewallet", "Attempt to recover private keys from a corrupt wallet file on startup");
29 4 : strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf("Spend unconfirmed change when sending transactions (default: %u)", DEFAULT_SPEND_ZEROCONF_CHANGE));
30 4 : strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)", 1));
31 3 : strUsage += HelpMessageOpt("-upgradewallet", "Upgrade wallet to latest format on startup");
32 3 : strUsage += HelpMessageOpt("-wallet=<path>", "Specify wallet database path. Can be specified multiple times to load multiple wallets. Path is interpreted relative to <walletdir> if it is not absolute, and will be created if it does not exist (as a directory containing a wallet.dat file and log files). For backwards compatibility this will also accept names of existing data files in <walletdir>.)");
33 4 : strUsage += HelpMessageOpt("-walletdir=<dir>", "Specify directory to hold wallets (default: <datadir>/wallets if it exists, otherwise <datadir>)");
34 4 : strUsage += HelpMessageOpt("-walletnotify=<cmd>", "Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)");
35 3 : strUsage += HelpMessageOpt("-zapwallettxes=<mode>", "Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup"
36 1 : "(1 = keep tx meta data e.g. payment request information, 2 = drop tx meta data)");
37 3 : strUsage += HelpMessageGroup("Mining/Staking options:");
38 4 : strUsage += HelpMessageOpt("-coldstaking=<n>", strprintf("Enable cold staking functionality (0-1, default: %u). Disabled if staking=0", DEFAULT_COLDSTAKING));
39 3 : strUsage += HelpMessageOpt("-gen", strprintf("Generate coins (default: %u)", DEFAULT_GENERATE));
40 4 : strUsage += HelpMessageOpt("-genproclimit=<n>", strprintf("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)", DEFAULT_GENERATE_PROCLIMIT));
41 5 : strUsage += HelpMessageOpt("-minstakesplit=<amt>", strprintf("Minimum positive amount (in PIV) allowed by GUI and RPC for the stake split threshold (default: %s)", FormatMoney(DEFAULT_MIN_STAKE_SPLIT_THRESHOLD)));
42 3 : strUsage += HelpMessageOpt("-staking=<n>", strprintf("Enable staking functionality (0-1, default: %u)", DEFAULT_STAKING));
43 1 : if (showDebug) {
44 0 : strUsage += HelpMessageGroup("Wallet debugging/testing options:");
45 0 : strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf("Flush database activity from memory pool to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE));
46 0 : strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET));
47 0 : strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB));
48 : }
49 :
50 1 : return strUsage;
51 : }
52 :
53 386 : bool WalletParameterInteraction()
54 : {
55 386 : if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
56 : return true;
57 : }
58 :
59 375 : if (gArgs.GetBoolArg("-sysperms", false)) {
60 0 : return UIError(strprintf(_("%s is not allowed in combination with enabled wallet functionality"), "-sysperms"));
61 : }
62 :
63 750 : gArgs.SoftSetArg("-wallet", "");
64 375 : const bool is_multiwallet = gArgs.GetArgs("-wallet").size() > 1;
65 :
66 375 : if (gArgs.GetBoolArg("-salvagewallet", false)) {
67 2 : if (is_multiwallet) {
68 6 : return UIError(strprintf(_("%s is only allowed with a single wallet file"), "-salvagewallet"));
69 : }
70 : // Rewrite just private keys: rescan to find transactions
71 0 : if (gArgs.SoftSetBoolArg("-rescan", true)) {
72 0 : LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting -rescan=1\n", __func__);
73 : }
74 : }
75 :
76 373 : bool zapwallettxes = gArgs.GetBoolArg("-zapwallettxes", false);
77 : // -zapwallettxes implies dropping the mempool on startup
78 381 : if (zapwallettxes && gArgs.SoftSetBoolArg("-persistmempool", false)) {
79 8 : LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -persistmempool=0\n", __func__, zapwallettxes);
80 : }
81 :
82 : // -zapwallettxes implies a rescan
83 373 : if (zapwallettxes) {
84 8 : if (is_multiwallet) {
85 9 : return UIError(strprintf(_("%s is only allowed with a single wallet file"), "-zapwallettxes"));
86 : }
87 5 : if (gArgs.SoftSetBoolArg("-rescan", true)) {
88 5 : LogPrintf("%s: parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1\n", __func__);
89 : }
90 : }
91 :
92 370 : if (is_multiwallet) {
93 8 : if (gArgs.GetBoolArg("-upgradewallet", false)) {
94 6 : return UIError(strprintf(_("%s is only allowed with a single wallet file"), "-upgradewallet"));
95 : }
96 : }
97 :
98 368 : if (gArgs.IsArgSet("-mintxfee")) {
99 0 : CAmount n = 0;
100 0 : if (ParseMoney(gArgs.GetArg("-mintxfee", ""), n) && n > 0)
101 0 : CWallet::minTxFee = CFeeRate(n);
102 : else
103 0 : return UIError(AmountErrMsg("mintxfee", gArgs.GetArg("-mintxfee", "")));
104 : }
105 368 : if (gArgs.IsArgSet("-paytxfee")) {
106 0 : CAmount nFeePerK = 0;
107 0 : if (!ParseMoney(gArgs.GetArg("-paytxfee", ""), nFeePerK))
108 0 : return UIError(AmountErrMsg("paytxfee", gArgs.GetArg("-paytxfee", "")));
109 0 : if (nFeePerK > nHighTransactionFeeWarning)
110 0 : UIWarning(strprintf(_("Warning: %s is set very high! This is the transaction fee you will pay if you send a transaction."), "-paytxfee"));
111 0 : payTxFee = CFeeRate(nFeePerK, 1000);
112 0 : if (payTxFee < ::minRelayTxFee) {
113 0 : return UIError(strprintf(_("Invalid amount for %s: '%s' (must be at least %s)"), "-paytxfee",
114 0 : gArgs.GetArg("-paytxfee", ""), ::minRelayTxFee.ToString()));
115 : }
116 : }
117 368 : if (gArgs.IsArgSet("-maxtxfee")) {
118 0 : CAmount nMaxFee = 0;
119 0 : if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee))
120 0 : return UIError(AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", "")));
121 0 : if (nMaxFee > nHighTransactionMaxFeeWarning)
122 0 : UIWarning(strprintf(_("Warning: %s is set very high! Fees this large could be paid on a single transaction."), "-maxtxfee"));
123 0 : maxTxFee = nMaxFee;
124 0 : if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee) {
125 0 : return UIError(strprintf(_("Invalid amount for %s: '%s' (must be at least the minimum relay fee of %s to prevent stuck transactions)"),
126 0 : "-maxtxfee", gArgs.GetArg("-maxtxfee", ""), ::minRelayTxFee.ToString()));
127 : }
128 : }
129 368 : if (gArgs.IsArgSet("-minstakesplit")) {
130 0 : CAmount n = 0;
131 0 : if (ParseMoney(gArgs.GetArg("-minstakesplit", ""), n) && n > 0)
132 0 : CWallet::minStakeSplitThreshold = n;
133 : else
134 0 : return UIError(AmountErrMsg("minstakesplit", gArgs.GetArg("-minstakesplit", "")));
135 : }
136 368 : nTxConfirmTarget = gArgs.GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
137 736 : bSpendZeroConfChange = gArgs.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
138 368 : bdisableSystemnotifications = gArgs.GetBoolArg("-disablesystemnotifications", false);
139 :
140 368 : return true;
141 : }
142 :
143 376 : bool WalletVerify()
144 : {
145 376 : if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
146 : return true;
147 : }
148 :
149 365 : if (gArgs.IsArgSet("-walletdir")) {
150 27 : fs::path wallet_dir = gArgs.GetArg("-walletdir", "");
151 11 : if (!fs::exists(wallet_dir)) {
152 6 : return UIError(strprintf(_("Specified -walletdir \"%s\" does not exist"), wallet_dir.string()));
153 7 : } else if (!fs::is_directory(wallet_dir)) {
154 6 : return UIError(strprintf(_("Specified -walletdir \"%s\" is not a directory"), wallet_dir.string()));
155 5 : } else if (!wallet_dir.is_absolute()) {
156 3 : return UIError(strprintf(_("Specified -walletdir \"%s\" is a relative path"), wallet_dir.string()));
157 : }
158 : }
159 :
160 360 : LogPrintf("Using wallet directory %s\n", GetWalletDir().string());
161 :
162 360 : uiInterface.InitMessage(_("Verifying wallet(s)..."));
163 :
164 : // Keep track of each wallet absolute path to detect duplicates.
165 735 : std::set<fs::path> wallet_paths;
166 :
167 735 : for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
168 754 : auto opRes = VerifyWalletPath(walletFile);
169 380 : if (!opRes) return UIError(opRes.getError());
170 :
171 1133 : fs::path wallet_path = fs::absolute(walletFile, GetWalletDir());
172 378 : if (!wallet_paths.insert(wallet_path).second) {
173 4 : return UIError(strprintf(_("Error loading wallet %s. Duplicate %s filename specified."), walletFile, "-wallet"));
174 : }
175 :
176 752 : std::string strError;
177 377 : if (!WalletBatch::VerifyEnvironment(wallet_path, strError)) {
178 5 : return UIError(strError);
179 : }
180 :
181 374 : if (gArgs.GetBoolArg("-salvagewallet", false)) {
182 : // Recover readable keypairs:
183 1 : CWallet dummyWallet("dummy", WalletDatabase::CreateDummy());
184 0 : std::string backup_filename;
185 : // Even if we don't use this lock in this function, we want to preserve
186 : // lock order in LoadToWallet if query of chain state is needed to know
187 : // tx status. If lock can't be taken, tx confirmation status may be not
188 : // reliable.
189 0 : LOCK(cs_main);
190 0 : if (!WalletBatch::Recover(wallet_path, (void *)&dummyWallet, WalletBatch::RecoverKeysOnlyFilter, backup_filename)) {
191 0 : return false;
192 : }
193 : }
194 :
195 748 : std::string strWarning;
196 374 : bool dbV = WalletBatch::VerifyDatabaseFile(wallet_path, strWarning, strError);
197 374 : if (!strWarning.empty()) {
198 0 : UIWarning(strWarning);
199 : }
200 374 : if (!dbV) {
201 2 : return UIError(strError);
202 : }
203 : }
204 :
205 355 : return true;
206 : }
207 :
208 356 : bool InitLoadWallet()
209 : {
210 356 : if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
211 11 : LogPrintf("Wallet disabled!\n");
212 11 : return true;
213 : }
214 :
215 707 : for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
216 : // create/load wallet
217 1092 : CWallet * const pwallet = CWallet::CreateWalletFromFile(walletFile, fs::absolute(walletFile, GetWalletDir()));
218 362 : if (!pwallet) {
219 0 : return false;
220 : }
221 :
222 : // add to wallets in use
223 362 : vpwallets.emplace_back(pwallet);
224 : }
225 :
226 : // automatic backup
227 : // do this after loading all wallets, so unique fileids are checked properly
228 705 : for (CWallet* pwallet: vpwallets) {
229 722 : std::string strWarning, strError;
230 361 : if (!AutoBackupWallet(*pwallet, strWarning, strError)) {
231 74 : if (!strWarning.empty()) {
232 0 : UIWarning(strprintf("%s: %s", pwallet->GetName(), strWarning));
233 : }
234 74 : if (!strError.empty()) {
235 0 : return UIError(strprintf("%s: %s", pwallet->GetName(), strError));
236 : }
237 : }
238 : }
239 :
240 344 : return true;
241 : }
|