diff --git a/doc/release-notes.md b/doc/release-notes.md
index b3de6650b..221b6b23a 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -1,28 +1,29 @@
Bitcoin ABC version 0.19.7 is now available from:
This release includes the following features and fixes:
- `-includeconf=` can be used to include additional configuration files.
Only works inside the `bitcoin.conf` file, not inside included files or from
command-line. Multiple files may be included. Can be disabled from command-
line via `-noincludeconf`. Note that multi-argument commands like
`-includeconf` will override preceding `-noincludeconf`, i.e.
noincludeconf=1
includeconf=relative.conf
as bitcoin.conf will still include `relative.conf`.
- The `createrawtransaction` RPC will now accept an array or dictionary (kept for compatibility) for the `outputs` parameter. This means the order of transaction outputs can be specified by the client.
- The new RPC `testmempoolaccept` can be used to test acceptance of a transaction to the mempool without adding it.
- An `initialblockdownload` boolean has been added to the `getblockchaininfo` RPC to indicate whether the node is currently in IBD or not.
+ - The '-usehd' option has been removed. It is no longer possible to create a non HD wallet.
Transaction index changes
-------------------------
The transaction index is now built separately from the main node procedure,
meaning the `-txindex` flag can be toggled without a full reindex. If bitcoind
is run with `-txindex` on a node that is already partially or fully synced
without one, the transaction index will be built in the background and become
available once caught up. When switching from running `-txindex` to running
without the flag, the transaction index database will *not* be deleted
automatically, meaning it could be turned back on at a later time without a full
resync.
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index 8ecd6506b..033def6f9 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -1,430 +1,424 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2017 The Bitcoin Core developers
// Copyright (c) 2018 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
class WalletInit : public WalletInitInterface {
public:
//! Return the wallets help message.
void AddWalletOptions() const override;
//! Wallets parameter interaction
bool ParameterInteraction() const override;
//! Register wallet RPCs.
void RegisterRPC(CRPCTable &tableRPC) const override;
//! Responsible for reading and validating the -wallet arguments and
//! verifying the wallet database.
// This function will perform salvage on the wallet if requested, as long
// as only one wallet is being loaded (WalletParameterInteraction forbids
// -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet).
bool Verify(const CChainParams &chainParams) const override;
//! Load wallet databases.
bool Open(const CChainParams &chainParams) const override;
//! Complete startup of wallets.
void Start(CScheduler &scheduler) const override;
//! Flush all wallets in preparation for shutdown.
void Flush() const override;
//! Stop all wallets. Wallets will be flushed first.
void Stop() const override;
//! Close all wallets.
void Close() const override;
};
const WalletInitInterface &g_wallet_init_interface = WalletInit();
void WalletInit::AddWalletOptions() const {
gArgs.AddArg("-disablewallet",
_("Do not load the wallet and disable wallet RPC calls"),
false, OptionsCategory::WALLET);
gArgs.AddArg("-keypool=",
strprintf(_("Set key pool size to (default: %u)"),
DEFAULT_KEYPOOL_SIZE),
false, OptionsCategory::WALLET);
gArgs.AddArg("-fallbackfee=",
strprintf(_("A fee rate (in %s/kB) that will be used when fee "
"estimation has insufficient data (default: %s)"),
CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)),
false, OptionsCategory::WALLET);
gArgs.AddArg(
"-paytxfee=",
strprintf(
_("Fee (in %s/kB) to add to transactions you send (default: %s)"),
CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK())),
false, OptionsCategory::WALLET);
gArgs.AddArg(
"-rescan",
_("Rescan the block chain for missing wallet transactions on startup"),
false, OptionsCategory::WALLET);
gArgs.AddArg(
"-salvagewallet",
_("Attempt to recover private keys from a corrupt wallet on startup"),
false, OptionsCategory::WALLET);
gArgs.AddArg("-spendzeroconfchange",
strprintf(_("Spend unconfirmed change when sending "
"transactions (default: %d)"),
DEFAULT_SPEND_ZEROCONF_CHANGE),
false, OptionsCategory::WALLET);
- gArgs.AddArg(
- "-usehd",
- _("Use hierarchical deterministic key generation (HD) after BIP32. "
- "Only has effect during wallet creation/first start") +
- " " + strprintf(_("(default: %d)"), DEFAULT_USE_HD_WALLET),
- false, OptionsCategory::WALLET);
gArgs.AddArg("-upgradewallet",
_("Upgrade wallet to latest format on startup"), false,
OptionsCategory::WALLET);
gArgs.AddArg("-wallet=",
_("Specify wallet file (within data directory)") + " " +
strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT),
false, OptionsCategory::WALLET);
gArgs.AddArg("-walletbroadcast",
_("Make the wallet broadcast transactions") + " " +
strprintf(_("(default: %d)"), DEFAULT_WALLETBROADCAST),
false, OptionsCategory::WALLET);
gArgs.AddArg("-walletdir=",
_("Specify directory to hold wallets (default: "
"/wallets if it exists, otherwise )"),
false, OptionsCategory::WALLET);
gArgs.AddArg("-walletnotify=",
_("Execute command when a wallet transaction changes (%s in "
"cmd is replaced by TxID)"),
false, OptionsCategory::WALLET);
gArgs.AddArg("-zapwallettxes=",
_("Delete all wallet transactions and only recover those "
"parts of the blockchain through -rescan on startup") +
" " +
_("(1 = keep tx meta data e.g. account owner and payment "
"request information, 2 = drop tx meta data)"),
false, OptionsCategory::WALLET);
gArgs.AddArg("-dblogsize=",
strprintf("Flush wallet database activity from memory to disk "
"log every megabytes (default: %u)",
DEFAULT_WALLET_DBLOGSIZE),
true, OptionsCategory::WALLET_DEBUG_TEST);
gArgs.AddArg(
"-flushwallet",
strprintf("Run a thread to flush wallet periodically (default: %d)",
DEFAULT_FLUSHWALLET),
true, OptionsCategory::WALLET_DEBUG_TEST);
gArgs.AddArg("-privdb",
strprintf("Sets the DB_PRIVATE flag in the wallet db "
"environment (default: %d)",
DEFAULT_WALLET_PRIVDB),
true, OptionsCategory::WALLET_DEBUG_TEST);
gArgs.AddArg("-walletrejectlongchains",
strprintf(_("Wallet will not create transactions that violate "
"mempool chain limits (default: %d)"),
DEFAULT_WALLET_REJECT_LONG_CHAINS),
true, OptionsCategory::WALLET_DEBUG_TEST);
}
bool WalletInit::ParameterInteraction() const {
CFeeRate minRelayTxFee = GetConfig().GetMinFeePerKB();
gArgs.SoftSetArg("-wallet", DEFAULT_WALLET_DAT);
const bool is_multiwallet = gArgs.GetArgs("-wallet").size() > 1;
if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
return true;
}
if (gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) &&
gArgs.SoftSetBoolArg("-walletbroadcast", false)) {
LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting "
"-walletbroadcast=0\n",
__func__);
}
if (gArgs.GetBoolArg("-salvagewallet", false) &&
gArgs.SoftSetBoolArg("-rescan", true)) {
if (is_multiwallet) {
return InitError(
strprintf("%s is only allowed with a single wallet file",
"-salvagewallet"));
}
// Rewrite just private keys: rescan to find transactions
LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting "
"-rescan=1\n",
__func__);
}
int zapwallettxes = gArgs.GetArg("-zapwallettxes", 0);
// -zapwallettxes implies dropping the mempool on startup
if (zapwallettxes != 0 && gArgs.SoftSetBoolArg("-persistmempool", false)) {
LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting "
"-persistmempool=0\n",
__func__, zapwallettxes);
}
// -zapwallettxes implies a rescan
if (zapwallettxes != 0) {
if (is_multiwallet) {
return InitError(
strprintf("%s is only allowed with a single wallet file",
"-zapwallettxes"));
}
if (gArgs.SoftSetBoolArg("-rescan", true)) {
LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting "
"-rescan=1\n",
__func__, zapwallettxes);
}
LogPrintf("%s: parameter interaction: -zapwallettxes= -> setting "
"-rescan=1\n",
__func__);
}
if (is_multiwallet) {
if (gArgs.GetBoolArg("-upgradewallet", false)) {
return InitError(
strprintf("%s is only allowed with a single wallet file",
"-upgradewallet"));
}
}
if (gArgs.GetBoolArg("-sysperms", false)) {
return InitError("-sysperms is not allowed in combination with enabled "
"wallet functionality");
}
if (gArgs.GetArg("-prune", 0) && gArgs.GetBoolArg("-rescan", false)) {
return InitError(
_("Rescans are not possible in pruned mode. You will need to use "
"-reindex which will download the whole blockchain again."));
}
if (minRelayTxFee.GetFeePerK() > HIGH_TX_FEE_PER_KB) {
InitWarning(
AmountHighWarn("-minrelaytxfee") + " " +
_("The wallet will avoid paying less than the minimum relay fee."));
}
if (gArgs.IsArgSet("-fallbackfee")) {
Amount nFeePerK = Amount::zero();
if (!ParseMoney(gArgs.GetArg("-fallbackfee", ""), nFeePerK)) {
return InitError(
strprintf(_("Invalid amount for -fallbackfee=: '%s'"),
gArgs.GetArg("-fallbackfee", "")));
}
if (nFeePerK > HIGH_TX_FEE_PER_KB) {
InitWarning(AmountHighWarn("-fallbackfee") + " " +
_("This is the transaction fee you may pay when fee "
"estimates are not available."));
}
CWallet::fallbackFee = CFeeRate(nFeePerK);
}
if (gArgs.IsArgSet("-paytxfee")) {
Amount nFeePerK = Amount::zero();
if (!ParseMoney(gArgs.GetArg("-paytxfee", ""), nFeePerK)) {
return InitError(
AmountErrMsg("paytxfee", gArgs.GetArg("-paytxfee", "")));
}
if (nFeePerK > HIGH_TX_FEE_PER_KB) {
InitWarning(AmountHighWarn("-paytxfee") + " " +
_("This is the transaction fee you will pay if you "
"send a transaction."));
}
payTxFee = CFeeRate(nFeePerK, 1000);
if (payTxFee < minRelayTxFee) {
return InitError(strprintf(
_("Invalid amount for -paytxfee=: '%s' (must "
"be at least %s)"),
gArgs.GetArg("-paytxfee", ""), minRelayTxFee.ToString()));
}
}
if (gArgs.IsArgSet("-maxtxfee")) {
Amount nMaxFee = Amount::zero();
if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee)) {
return InitError(
AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", "")));
}
if (nMaxFee > HIGH_MAX_TX_FEE) {
InitWarning(_("-maxtxfee is set very high! Fees this large could "
"be paid on a single transaction."));
}
maxTxFee = nMaxFee;
if (CFeeRate(maxTxFee, 1000) < minRelayTxFee) {
return InitError(strprintf(
_("Invalid amount for -maxtxfee=: '%s' (must "
"be at least the minrelay fee of %s to prevent "
"stuck transactions)"),
gArgs.GetArg("-maxtxfee", ""), minRelayTxFee.ToString()));
}
}
bSpendZeroConfChange =
gArgs.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
return true;
}
void WalletInit::RegisterRPC(CRPCTable &t) const {
if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
return;
}
RegisterWalletRPCCommands(t);
RegisterDumpRPCCommands(t);
}
bool WalletInit::Verify(const CChainParams &chainParams) const {
if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
return true;
}
if (gArgs.IsArgSet("-walletdir")) {
fs::path wallet_dir = gArgs.GetArg("-walletdir", "");
if (!fs::exists(wallet_dir)) {
return InitError(
strprintf(_("Specified -walletdir \"%s\" does not exist"),
wallet_dir.string()));
} else if (!fs::is_directory(wallet_dir)) {
return InitError(
strprintf(_("Specified -walletdir \"%s\" is not a directory"),
wallet_dir.string()));
} else if (!wallet_dir.is_absolute()) {
return InitError(
strprintf(_("Specified -walletdir \"%s\" is a relative path"),
wallet_dir.string()));
}
}
LogPrintf("Using wallet directory %s\n", GetWalletDir().string());
uiInterface.InitMessage(_("Verifying wallet(s)..."));
// Keep track of each wallet absolute path to detect duplicates.
std::set wallet_paths;
for (const std::string &walletFile : gArgs.GetArgs("-wallet")) {
if (fs::path(walletFile).filename() != walletFile) {
return InitError(
strprintf(_("Error loading wallet %s. -wallet parameter must "
"only specify a filename (not a path)."),
walletFile));
}
if (SanitizeString(walletFile, SAFE_CHARS_FILENAME) != walletFile) {
return InitError(strprintf(_("Error loading wallet %s. Invalid "
"characters in -wallet filename."),
walletFile));
}
fs::path wallet_path = fs::absolute(walletFile, GetWalletDir());
if (fs::exists(wallet_path) && (!fs::is_regular_file(wallet_path) ||
fs::is_symlink(wallet_path))) {
return InitError(strprintf(_("Error loading wallet %s. -wallet "
"filename must be a regular file."),
walletFile));
}
if (!wallet_paths.insert(wallet_path).second) {
return InitError(strprintf(_("Error loading wallet %s. Duplicate "
"-wallet filename specified."),
walletFile));
}
std::string strError;
if (!CWalletDB::VerifyEnvironment(walletFile, GetWalletDir().string(),
strError)) {
return InitError(strError);
}
if (gArgs.GetBoolArg("-salvagewallet", false)) {
// Recover readable keypairs:
CWallet dummyWallet(chainParams);
std::string backup_filename;
if (!CWalletDB::Recover(walletFile, (void *)&dummyWallet,
CWalletDB::RecoverKeysOnlyFilter,
backup_filename)) {
return false;
}
}
std::string strWarning;
bool dbV = CWalletDB::VerifyDatabaseFile(
walletFile, GetWalletDir().string(), strWarning, strError);
if (!strWarning.empty()) {
InitWarning(strWarning);
}
if (!dbV) {
InitError(strError);
return false;
}
}
return true;
}
bool WalletInit::Open(const CChainParams &chainParams) const {
if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
LogPrintf("Wallet disabled!\n");
return true;
}
for (const std::string &walletFile : gArgs.GetArgs("-wallet")) {
CWallet *const pwallet =
CWallet::CreateWalletFromFile(chainParams, walletFile);
if (!pwallet) {
return false;
}
vpwallets.push_back(pwallet);
}
return true;
}
void WalletInit::Start(CScheduler &scheduler) const {
for (CWalletRef pwallet : vpwallets) {
pwallet->postInitProcess(scheduler);
}
}
void WalletInit::Flush() const {
for (CWalletRef pwallet : vpwallets) {
pwallet->Flush(false);
}
}
void WalletInit::Stop() const {
for (CWalletRef pwallet : vpwallets) {
pwallet->Flush(true);
}
}
void WalletInit::Close() const {
for (CWalletRef pwallet : vpwallets) {
delete pwallet;
}
vpwallets.clear();
}
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index d34181a4f..9d9b114a2 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1,4513 +1,4509 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include // for IsDeprecatedRPCEnabled
#include
#include