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