|
10 | 10 | #include "utilmoneystr.h"
|
11 | 11 | #include "validation.h"
|
12 | 12 | #include "wallet/wallet.h"
|
| 13 | + |
| 14 | +std::string GetWalletHelpString(bool showDebug) |
| 15 | +{ |
| 16 | + std::string strUsage = HelpMessageGroup(_("Wallet options:")); |
| 17 | + strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls")); |
| 18 | + strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), DEFAULT_KEYPOOL_SIZE)); |
| 19 | + strUsage += HelpMessageOpt("-fallbackfee=<amt>", strprintf(_("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)"), |
| 20 | + CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE))); |
| 21 | + 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). " |
| 22 | + "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"), |
| 23 | + CURRENCY_UNIT, FormatMoney(DEFAULT_DISCARD_FEE))); |
| 24 | + strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"), |
| 25 | + CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE))); |
| 26 | + strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"), |
| 27 | + CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK()))); |
| 28 | + strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions on startup")); |
| 29 | + strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet on startup")); |
| 30 | + strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE)); |
| 31 | + 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)); |
| 32 | + strUsage += HelpMessageOpt("-usehd", _("Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start") + " " + strprintf(_("(default: %u)"), DEFAULT_USE_HD_WALLET)); |
| 33 | + strUsage += HelpMessageOpt("-walletrbf", strprintf(_("Send transactions with full-RBF opt-in enabled (default: %u)"), DEFAULT_WALLET_RBF)); |
| 34 | + strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup")); |
| 35 | + strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT)); |
| 36 | + strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST)); |
| 37 | + strUsage += HelpMessageOpt("-walletnotify=<cmd>", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)")); |
| 38 | + strUsage += HelpMessageOpt("-zapwallettxes=<mode>", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") + |
| 39 | + " " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)")); |
| 40 | + |
| 41 | + if (showDebug) |
| 42 | + { |
| 43 | + strUsage += HelpMessageGroup(_("Wallet debugging/testing options:")); |
| 44 | + |
| 45 | + strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE)); |
| 46 | + strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET)); |
| 47 | + strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB)); |
| 48 | + strUsage += HelpMessageOpt("-walletrejectlongchains", strprintf(_("Wallet will not create transactions that violate mempool chain limits (default: %u)"), DEFAULT_WALLET_REJECT_LONG_CHAINS)); |
| 49 | + } |
| 50 | + |
| 51 | + return strUsage; |
| 52 | +} |
| 53 | + |
| 54 | +bool WalletParameterInteraction() |
| 55 | +{ |
| 56 | + gArgs.SoftSetArg("-wallet", DEFAULT_WALLET_DAT); |
| 57 | + const bool is_multiwallet = gArgs.GetArgs("-wallet").size() > 1; |
| 58 | + |
| 59 | + if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) |
| 60 | + return true; |
| 61 | + |
| 62 | + if (gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && gArgs.SoftSetBoolArg("-walletbroadcast", false)) { |
| 63 | + LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__); |
| 64 | + } |
| 65 | + |
| 66 | + if (gArgs.GetBoolArg("-salvagewallet", false)) { |
| 67 | + if (is_multiwallet) { |
| 68 | + return InitError(strprintf("%s is only allowed with a single wallet file", "-salvagewallet")); |
| 69 | + } |
| 70 | + // Rewrite just private keys: rescan to find transactions |
| 71 | + if (gArgs.SoftSetBoolArg("-rescan", true)) { |
| 72 | + LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting -rescan=1\n", __func__); |
| 73 | + } |
| 74 | + } |
| 75 | + |
| 76 | + int zapwallettxes = gArgs.GetArg("-zapwallettxes", 0); |
| 77 | + // -zapwallettxes implies dropping the mempool on startup |
| 78 | + if (zapwallettxes != 0 && gArgs.SoftSetBoolArg("-persistmempool", false)) { |
| 79 | + LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -persistmempool=0\n", __func__, zapwallettxes); |
| 80 | + } |
| 81 | + |
| 82 | + // -zapwallettxes implies a rescan |
| 83 | + if (zapwallettxes != 0) { |
| 84 | + if (is_multiwallet) { |
| 85 | + return InitError(strprintf("%s is only allowed with a single wallet file", "-zapwallettxes")); |
| 86 | + } |
| 87 | + if (gArgs.SoftSetBoolArg("-rescan", true)) { |
| 88 | + LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -rescan=1\n", __func__, zapwallettxes); |
| 89 | + } |
| 90 | + } |
| 91 | + |
| 92 | + if (is_multiwallet) { |
| 93 | + if (gArgs.GetBoolArg("-upgradewallet", false)) { |
| 94 | + return InitError(strprintf("%s is only allowed with a single wallet file", "-upgradewallet")); |
| 95 | + } |
| 96 | + } |
| 97 | + |
| 98 | + if (gArgs.GetBoolArg("-sysperms", false)) |
| 99 | + return InitError("-sysperms is not allowed in combination with enabled wallet functionality"); |
| 100 | + if (gArgs.GetArg("-prune", 0) && gArgs.GetBoolArg("-rescan", false)) |
| 101 | + return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.")); |
| 102 | + |
| 103 | + if (::minRelayTxFee.GetFeePerK() > HIGH_TX_FEE_PER_KB) |
| 104 | + InitWarning(AmountHighWarn("-minrelaytxfee") + " " + |
| 105 | + _("The wallet will avoid paying less than the minimum relay fee.")); |
| 106 | + |
| 107 | + if (gArgs.IsArgSet("-mintxfee")) |
| 108 | + { |
| 109 | + CAmount n = 0; |
| 110 | + if (!ParseMoney(gArgs.GetArg("-mintxfee", ""), n) || 0 == n) |
| 111 | + return InitError(AmountErrMsg("mintxfee", gArgs.GetArg("-mintxfee", ""))); |
| 112 | + if (n > HIGH_TX_FEE_PER_KB) |
| 113 | + InitWarning(AmountHighWarn("-mintxfee") + " " + |
| 114 | + _("This is the minimum transaction fee you pay on every transaction.")); |
| 115 | + CWallet::minTxFee = CFeeRate(n); |
| 116 | + } |
| 117 | + if (gArgs.IsArgSet("-fallbackfee")) |
| 118 | + { |
| 119 | + CAmount nFeePerK = 0; |
| 120 | + if (!ParseMoney(gArgs.GetArg("-fallbackfee", ""), nFeePerK)) |
| 121 | + return InitError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), gArgs.GetArg("-fallbackfee", ""))); |
| 122 | + if (nFeePerK > HIGH_TX_FEE_PER_KB) |
| 123 | + InitWarning(AmountHighWarn("-fallbackfee") + " " + |
| 124 | + _("This is the transaction fee you may pay when fee estimates are not available.")); |
| 125 | + CWallet::fallbackFee = CFeeRate(nFeePerK); |
| 126 | + } |
| 127 | + if (gArgs.IsArgSet("-discardfee")) |
| 128 | + { |
| 129 | + CAmount nFeePerK = 0; |
| 130 | + if (!ParseMoney(gArgs.GetArg("-discardfee", ""), nFeePerK)) |
| 131 | + return InitError(strprintf(_("Invalid amount for -discardfee=<amount>: '%s'"), gArgs.GetArg("-discardfee", ""))); |
| 132 | + if (nFeePerK > HIGH_TX_FEE_PER_KB) |
| 133 | + InitWarning(AmountHighWarn("-discardfee") + " " + |
| 134 | + _("This is the transaction fee you may discard if change is smaller than dust at this level")); |
| 135 | + CWallet::m_discard_rate = CFeeRate(nFeePerK); |
| 136 | + } |
| 137 | + if (gArgs.IsArgSet("-paytxfee")) |
| 138 | + { |
| 139 | + CAmount nFeePerK = 0; |
| 140 | + if (!ParseMoney(gArgs.GetArg("-paytxfee", ""), nFeePerK)) |
| 141 | + return InitError(AmountErrMsg("paytxfee", gArgs.GetArg("-paytxfee", ""))); |
| 142 | + if (nFeePerK > HIGH_TX_FEE_PER_KB) |
| 143 | + InitWarning(AmountHighWarn("-paytxfee") + " " + |
| 144 | + _("This is the transaction fee you will pay if you send a transaction.")); |
| 145 | + |
| 146 | + payTxFee = CFeeRate(nFeePerK, 1000); |
| 147 | + if (payTxFee < ::minRelayTxFee) |
| 148 | + { |
| 149 | + return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"), |
| 150 | + gArgs.GetArg("-paytxfee", ""), ::minRelayTxFee.ToString())); |
| 151 | + } |
| 152 | + } |
| 153 | + if (gArgs.IsArgSet("-maxtxfee")) |
| 154 | + { |
| 155 | + CAmount nMaxFee = 0; |
| 156 | + if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee)) |
| 157 | + return InitError(AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", ""))); |
| 158 | + if (nMaxFee > HIGH_MAX_TX_FEE) |
| 159 | + InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction.")); |
| 160 | + maxTxFee = nMaxFee; |
| 161 | + if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee) |
| 162 | + { |
| 163 | + return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"), |
| 164 | + gArgs.GetArg("-maxtxfee", ""), ::minRelayTxFee.ToString())); |
| 165 | + } |
| 166 | + } |
| 167 | + nTxConfirmTarget = gArgs.GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET); |
| 168 | + bSpendZeroConfChange = gArgs.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE); |
| 169 | + fWalletRbf = gArgs.GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF); |
| 170 | + |
| 171 | + return true; |
| 172 | +} |
| 173 | + |
| 174 | +bool WalletVerify() |
| 175 | +{ |
| 176 | + if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) |
| 177 | + return true; |
| 178 | + |
| 179 | + uiInterface.InitMessage(_("Verifying wallet(s)...")); |
| 180 | + |
| 181 | + // Keep track of each wallet absolute path to detect duplicates. |
| 182 | + std::set<fs::path> wallet_paths; |
| 183 | + |
| 184 | + for (const std::string& walletFile : gArgs.GetArgs("-wallet")) { |
| 185 | + if (boost::filesystem::path(walletFile).filename() != walletFile) { |
| 186 | + return InitError(strprintf(_("Error loading wallet %s. -wallet parameter must only specify a filename (not a path)."), walletFile)); |
| 187 | + } |
| 188 | + |
| 189 | + if (SanitizeString(walletFile, SAFE_CHARS_FILENAME) != walletFile) { |
| 190 | + return InitError(strprintf(_("Error loading wallet %s. Invalid characters in -wallet filename."), walletFile)); |
| 191 | + } |
| 192 | + |
| 193 | + fs::path wallet_path = fs::absolute(walletFile, GetDataDir()); |
| 194 | + |
| 195 | + if (fs::exists(wallet_path) && (!fs::is_regular_file(wallet_path) || fs::is_symlink(wallet_path))) { |
| 196 | + return InitError(strprintf(_("Error loading wallet %s. -wallet filename must be a regular file."), walletFile)); |
| 197 | + } |
| 198 | + |
| 199 | + if (!wallet_paths.insert(wallet_path).second) { |
| 200 | + return InitError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), walletFile)); |
| 201 | + } |
| 202 | + |
| 203 | + std::string strError; |
| 204 | + if (!CWalletDB::VerifyEnvironment(walletFile, GetDataDir().string(), strError)) { |
| 205 | + return InitError(strError); |
| 206 | + } |
| 207 | + |
| 208 | + if (gArgs.GetBoolArg("-salvagewallet", false)) { |
| 209 | + // Recover readable keypairs: |
| 210 | + CWallet dummyWallet; |
| 211 | + std::string backup_filename; |
| 212 | + if (!CWalletDB::Recover(walletFile, (void *)&dummyWallet, CWalletDB::RecoverKeysOnlyFilter, backup_filename)) { |
| 213 | + return false; |
| 214 | + } |
| 215 | + } |
| 216 | + |
| 217 | + std::string strWarning; |
| 218 | + bool dbV = CWalletDB::VerifyDatabaseFile(walletFile, GetDataDir().string(), strWarning, strError); |
| 219 | + if (!strWarning.empty()) { |
| 220 | + InitWarning(strWarning); |
| 221 | + } |
| 222 | + if (!dbV) { |
| 223 | + InitError(strError); |
| 224 | + return false; |
| 225 | + } |
| 226 | + } |
| 227 | + |
| 228 | + return true; |
| 229 | +} |
| 230 | + |
| 231 | +bool InitLoadWallet() |
| 232 | +{ |
| 233 | + if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) { |
| 234 | + LogPrintf("Wallet disabled!\n"); |
| 235 | + return true; |
| 236 | + } |
| 237 | + |
| 238 | + for (const std::string& walletFile : gArgs.GetArgs("-wallet")) { |
| 239 | + CWallet * const pwallet = CWallet::CreateWalletFromFile(walletFile); |
| 240 | + if (!pwallet) { |
| 241 | + return false; |
| 242 | + } |
| 243 | + vpwallets.push_back(pwallet); |
| 244 | + } |
| 245 | + |
| 246 | + return true; |
| 247 | +} |
0 commit comments