1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2017 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.
6 #include <wallet/init.h>
10 #include <utilmoneystr.h>
11 #include <validation.h>
12 #include <wallet/rpcwallet.h>
13 #include <wallet/wallet.h>
14 #include <wallet/walletutil.h>
16 std::string
GetWalletHelpString(bool showDebug
)
18 std::string strUsage
= HelpMessageGroup(_("Wallet options:"));
19 strUsage
+= HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls"));
20 strUsage
+= HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), DEFAULT_KEYPOOL_SIZE
));
21 strUsage
+= HelpMessageOpt("-fallbackfee=<amt>", strprintf(_("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)"),
22 CURRENCY_UNIT
, FormatMoney(DEFAULT_FALLBACK_FEE
)));
23 strUsage
+= HelpMessageOpt("-discardfee=<amt>", strprintf(_("The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
24 "Note: An output is discarded if it is dust at this rate, but we will always discard up to the dust relay fee and a discard fee above that is limited by the fee estimate for the longest target"),
25 CURRENCY_UNIT
, FormatMoney(DEFAULT_DISCARD_FEE
)));
26 strUsage
+= HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"),
27 CURRENCY_UNIT
, FormatMoney(DEFAULT_TRANSACTION_MINFEE
)));
28 strUsage
+= HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"),
29 CURRENCY_UNIT
, FormatMoney(payTxFee
.GetFeePerK())));
30 strUsage
+= HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions on startup"));
31 strUsage
+= HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet on startup"));
32 strUsage
+= HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE
));
33 strUsage
+= HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET
));
34 strUsage
+= HelpMessageOpt("-walletrbf", strprintf(_("Send transactions with full-RBF opt-in enabled (RPC only, default: %u)"), DEFAULT_WALLET_RBF
));
35 strUsage
+= HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup"));
36 strUsage
+= HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT
));
37 strUsage
+= HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST
));
38 strUsage
+= HelpMessageOpt("-walletdir=<dir>", _("Specify directory to hold wallets (default: <datadir>/wallets if it exists, otherwise <datadir>)"));
39 strUsage
+= HelpMessageOpt("-walletnotify=<cmd>", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)"));
40 strUsage
+= HelpMessageOpt("-zapwallettxes=<mode>", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") +
41 " " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)"));
45 strUsage
+= HelpMessageGroup(_("Wallet debugging/testing options:"));
47 strUsage
+= HelpMessageOpt("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE
));
48 strUsage
+= HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET
));
49 strUsage
+= HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB
));
50 strUsage
+= HelpMessageOpt("-walletrejectlongchains", strprintf(_("Wallet will not create transactions that violate mempool chain limits (default: %u)"), DEFAULT_WALLET_REJECT_LONG_CHAINS
));
56 bool WalletParameterInteraction()
58 if (gArgs
.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET
)) {
59 for (const std::string
& wallet
: gArgs
.GetArgs("-wallet")) {
60 LogPrintf("%s: parameter interaction: -disablewallet -> ignoring -wallet=%s\n", __func__
, wallet
);
66 gArgs
.SoftSetArg("-wallet", DEFAULT_WALLET_DAT
);
67 const bool is_multiwallet
= gArgs
.GetArgs("-wallet").size() > 1;
69 if (gArgs
.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY
) && gArgs
.SoftSetBoolArg("-walletbroadcast", false)) {
70 LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__
);
73 if (gArgs
.GetBoolArg("-salvagewallet", false)) {
75 return InitError(strprintf("%s is only allowed with a single wallet file", "-salvagewallet"));
77 // Rewrite just private keys: rescan to find transactions
78 if (gArgs
.SoftSetBoolArg("-rescan", true)) {
79 LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting -rescan=1\n", __func__
);
83 int zapwallettxes
= gArgs
.GetArg("-zapwallettxes", 0);
84 // -zapwallettxes implies dropping the mempool on startup
85 if (zapwallettxes
!= 0 && gArgs
.SoftSetBoolArg("-persistmempool", false)) {
86 LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -persistmempool=0\n", __func__
, zapwallettxes
);
89 // -zapwallettxes implies a rescan
90 if (zapwallettxes
!= 0) {
92 return InitError(strprintf("%s is only allowed with a single wallet file", "-zapwallettxes"));
94 if (gArgs
.SoftSetBoolArg("-rescan", true)) {
95 LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -rescan=1\n", __func__
, zapwallettxes
);
100 if (gArgs
.GetBoolArg("-upgradewallet", false)) {
101 return InitError(strprintf("%s is only allowed with a single wallet file", "-upgradewallet"));
105 if (gArgs
.GetBoolArg("-sysperms", false))
106 return InitError("-sysperms is not allowed in combination with enabled wallet functionality");
107 if (gArgs
.GetArg("-prune", 0) && gArgs
.GetBoolArg("-rescan", false))
108 return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again."));
110 if (::minRelayTxFee
.GetFeePerK() > HIGH_TX_FEE_PER_KB
)
111 InitWarning(AmountHighWarn("-minrelaytxfee") + " " +
112 _("The wallet will avoid paying less than the minimum relay fee."));
114 if (gArgs
.IsArgSet("-mintxfee"))
117 if (!ParseMoney(gArgs
.GetArg("-mintxfee", ""), n
) || 0 == n
)
118 return InitError(AmountErrMsg("mintxfee", gArgs
.GetArg("-mintxfee", "")));
119 if (n
> HIGH_TX_FEE_PER_KB
)
120 InitWarning(AmountHighWarn("-mintxfee") + " " +
121 _("This is the minimum transaction fee you pay on every transaction."));
122 CWallet::minTxFee
= CFeeRate(n
);
124 if (gArgs
.IsArgSet("-fallbackfee"))
126 CAmount nFeePerK
= 0;
127 if (!ParseMoney(gArgs
.GetArg("-fallbackfee", ""), nFeePerK
))
128 return InitError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), gArgs
.GetArg("-fallbackfee", "")));
129 if (nFeePerK
> HIGH_TX_FEE_PER_KB
)
130 InitWarning(AmountHighWarn("-fallbackfee") + " " +
131 _("This is the transaction fee you may pay when fee estimates are not available."));
132 CWallet::fallbackFee
= CFeeRate(nFeePerK
);
134 if (gArgs
.IsArgSet("-discardfee"))
136 CAmount nFeePerK
= 0;
137 if (!ParseMoney(gArgs
.GetArg("-discardfee", ""), nFeePerK
))
138 return InitError(strprintf(_("Invalid amount for -discardfee=<amount>: '%s'"), gArgs
.GetArg("-discardfee", "")));
139 if (nFeePerK
> HIGH_TX_FEE_PER_KB
)
140 InitWarning(AmountHighWarn("-discardfee") + " " +
141 _("This is the transaction fee you may discard if change is smaller than dust at this level"));
142 CWallet::m_discard_rate
= CFeeRate(nFeePerK
);
144 if (gArgs
.IsArgSet("-paytxfee"))
146 CAmount nFeePerK
= 0;
147 if (!ParseMoney(gArgs
.GetArg("-paytxfee", ""), nFeePerK
))
148 return InitError(AmountErrMsg("paytxfee", gArgs
.GetArg("-paytxfee", "")));
149 if (nFeePerK
> HIGH_TX_FEE_PER_KB
)
150 InitWarning(AmountHighWarn("-paytxfee") + " " +
151 _("This is the transaction fee you will pay if you send a transaction."));
153 payTxFee
= CFeeRate(nFeePerK
, 1000);
154 if (payTxFee
< ::minRelayTxFee
)
156 return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
157 gArgs
.GetArg("-paytxfee", ""), ::minRelayTxFee
.ToString()));
160 if (gArgs
.IsArgSet("-maxtxfee"))
163 if (!ParseMoney(gArgs
.GetArg("-maxtxfee", ""), nMaxFee
))
164 return InitError(AmountErrMsg("maxtxfee", gArgs
.GetArg("-maxtxfee", "")));
165 if (nMaxFee
> HIGH_MAX_TX_FEE
)
166 InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
168 if (CFeeRate(maxTxFee
, 1000) < ::minRelayTxFee
)
170 return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
171 gArgs
.GetArg("-maxtxfee", ""), ::minRelayTxFee
.ToString()));
174 nTxConfirmTarget
= gArgs
.GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET
);
175 bSpendZeroConfChange
= gArgs
.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE
);
176 fWalletRbf
= gArgs
.GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF
);
181 void RegisterWalletRPC(CRPCTable
&t
)
183 if (gArgs
.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET
)) {
187 RegisterWalletRPCCommands(t
);
192 if (gArgs
.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET
)) {
196 if (gArgs
.IsArgSet("-walletdir") && !fs::is_directory(GetWalletDir())) {
197 if (fs::exists(fs::system_complete(gArgs
.GetArg("-walletdir", "")))) {
198 return InitError(strprintf(_("Specified -walletdir \"%s\" is not a directory"), gArgs
.GetArg("-walletdir", "").c_str()));
200 return InitError(strprintf(_("Specified -walletdir \"%s\" does not exist"), gArgs
.GetArg("-walletdir", "").c_str()));
203 LogPrintf("Using wallet directory %s\n", GetWalletDir().string());
205 uiInterface
.InitMessage(_("Verifying wallet(s)..."));
207 // Keep track of each wallet absolute path to detect duplicates.
208 std::set
<fs::path
> wallet_paths
;
210 for (const std::string
& walletFile
: gArgs
.GetArgs("-wallet")) {
211 if (boost::filesystem::path(walletFile
).filename() != walletFile
) {
212 return InitError(strprintf(_("Error loading wallet %s. -wallet parameter must only specify a filename (not a path)."), walletFile
));
215 if (SanitizeString(walletFile
, SAFE_CHARS_FILENAME
) != walletFile
) {
216 return InitError(strprintf(_("Error loading wallet %s. Invalid characters in -wallet filename."), walletFile
));
219 fs::path wallet_path
= fs::absolute(walletFile
, GetWalletDir());
221 if (fs::exists(wallet_path
) && (!fs::is_regular_file(wallet_path
) || fs::is_symlink(wallet_path
))) {
222 return InitError(strprintf(_("Error loading wallet %s. -wallet filename must be a regular file."), walletFile
));
225 if (!wallet_paths
.insert(wallet_path
).second
) {
226 return InitError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), walletFile
));
229 std::string strError
;
230 if (!CWalletDB::VerifyEnvironment(walletFile
, GetWalletDir().string(), strError
)) {
231 return InitError(strError
);
234 if (gArgs
.GetBoolArg("-salvagewallet", false)) {
235 // Recover readable keypairs:
237 std::string backup_filename
;
238 if (!CWalletDB::Recover(walletFile
, (void *)&dummyWallet
, CWalletDB::RecoverKeysOnlyFilter
, backup_filename
)) {
243 std::string strWarning
;
244 bool dbV
= CWalletDB::VerifyDatabaseFile(walletFile
, GetWalletDir().string(), strWarning
, strError
);
245 if (!strWarning
.empty()) {
246 InitWarning(strWarning
);
259 if (gArgs
.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET
)) {
260 LogPrintf("Wallet disabled!\n");
264 for (const std::string
& walletFile
: gArgs
.GetArgs("-wallet")) {
265 CWallet
* const pwallet
= CWallet::CreateWalletFromFile(walletFile
);
269 vpwallets
.push_back(pwallet
);
275 void StartWallets(CScheduler
& scheduler
) {
276 for (CWalletRef pwallet
: vpwallets
) {
277 pwallet
->postInitProcess(scheduler
);
281 void FlushWallets() {
282 for (CWalletRef pwallet
: vpwallets
) {
283 pwallet
->Flush(false);
288 for (CWalletRef pwallet
: vpwallets
) {
289 pwallet
->Flush(true);
293 void CloseWallets() {
294 for (CWalletRef pwallet
: vpwallets
) {