aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/addrdb.cpp3
-rw-r--r--src/chainparams.cpp6
-rw-r--r--src/chainparams.h6
-rw-r--r--src/compat/endian.h45
-rw-r--r--src/consensus/params.h4
-rw-r--r--src/init.cpp2
-rw-r--r--src/interfaces/node.cpp2
-rw-r--r--src/interfaces/wallet.h2
-rw-r--r--src/logging.cpp283
-rw-r--r--src/logging.h125
-rw-r--r--src/net_processing.cpp12
-rw-r--r--src/qt/test/wallettests.cpp6
-rw-r--r--src/rpc/mining.cpp2
-rw-r--r--src/rpc/misc.cpp2
-rw-r--r--src/test/test_bitcoin.cpp2
-rw-r--r--src/test/util_tests.cpp2
-rw-r--r--src/util.cpp298
-rw-r--r--src/util.h111
-rw-r--r--src/validation.cpp111
-rw-r--r--src/validation.h3
-rw-r--r--src/wallet/init.cpp12
-rw-r--r--src/wallet/rpcwallet.cpp18
-rw-r--r--src/wallet/test/wallet_tests.cpp12
-rw-r--r--src/wallet/wallet.cpp40
-rw-r--r--src/wallet/wallet.h27
-rw-r--r--src/wallet/walletdb.cpp2
27 files changed, 675 insertions, 465 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 1bbb92bf42..521687eb45 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -113,6 +113,7 @@ BITCOIN_CORE_H = \
keystore.h \
dbwrapper.h \
limitedmap.h \
+ logging.h \
memusage.h \
merkleblock.h \
miner.h \
@@ -364,6 +365,7 @@ libbitcoin_util_a_SOURCES = \
fs.cpp \
interfaces/handler.cpp \
interfaces/node.cpp \
+ logging.cpp \
random.cpp \
rpc/protocol.cpp \
rpc/util.cpp \
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
index e4620e63c6..59305ff187 100644
--- a/src/addrdb.cpp
+++ b/src/addrdb.cpp
@@ -49,7 +49,8 @@ bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data
// Serialize
if (!SerializeDB(fileout, data)) return false;
- FileCommit(fileout.Get());
+ if (!FileCommit(fileout.Get()))
+ return error("%s: Failed to flush file %s", __func__, pathTmp.string());
fileout.fclose();
// replace existing file, if any, with new file
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 6067503b0b..121d95af90 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -75,7 +75,7 @@ public:
CMainParams() {
strNetworkID = "main";
consensus.nSubsidyHalvingInterval = 210000;
- consensus.BIP16Height = 173805; // 00000000000000ce80a7e057163a4db1d5ad7b20fb6f598c9597b9665c8fb0d4 - April 1, 2012
+ consensus.BIP16Exception = uint256S("0x00000000000002dc756eebf4f49723ed8d30cc28a5f108eb94b1ba88ac4f9c22");
consensus.BIP34Height = 227931;
consensus.BIP34Hash = uint256S("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8");
consensus.BIP65Height = 388381; // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0
@@ -190,7 +190,7 @@ public:
CTestNetParams() {
strNetworkID = "test";
consensus.nSubsidyHalvingInterval = 210000;
- consensus.BIP16Height = 514; // 00000000040b4e986385315e14bee30ad876d8b47f748025b26683116d21aa65
+ consensus.BIP16Exception = uint256S("0x00000000dd30457c001f4095d208cc1296b0eed002427aa599874af7a432b105");
consensus.BIP34Height = 21111;
consensus.BIP34Hash = uint256S("0x0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8");
consensus.BIP65Height = 581885; // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6
@@ -283,7 +283,7 @@ public:
CRegTestParams() {
strNetworkID = "regtest";
consensus.nSubsidyHalvingInterval = 150;
- consensus.BIP16Height = 0; // always enforce P2SH BIP16 on regtest
+ consensus.BIP16Exception = uint256();
consensus.BIP34Height = 100000000; // BIP34 has not activated on regtest (far in the future so block v1 are not rejected in tests)
consensus.BIP34Hash = uint256();
consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in rpc activation tests)
diff --git a/src/chainparams.h b/src/chainparams.h
index 6b1f813afb..dd029b9d5b 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -25,6 +25,12 @@ struct CCheckpointData {
MapCheckpoints mapCheckpoints;
};
+/**
+ * Holds various statistics on transactions within a chain. Used to estimate
+ * verification progress during chain sync.
+ *
+ * See also: CChainParams::TxData, GuessVerificationProgress.
+ */
struct ChainTxData {
int64_t nTime;
int64_t nTxCount;
diff --git a/src/compat/endian.h b/src/compat/endian.h
index e5c7e50223..4f244c3930 100644
--- a/src/compat/endian.h
+++ b/src/compat/endian.h
@@ -19,6 +19,51 @@
#include <sys/endian.h>
#endif
+#ifndef HAVE_CONFIG_H
+// While not technically a supported configuration, defaulting to defining these
+// DECLs when we were compiled without autotools makes it easier for other build
+// systems to build things like libbitcoinconsensus for strange targets.
+#ifdef htobe16
+#define HAVE_DECL_HTOBE16 1
+#endif
+#ifdef htole16
+#define HAVE_DECL_HTOLE16 1
+#endif
+#ifdef be16toh
+#define HAVE_DECL_BE16TOH 1
+#endif
+#ifdef le16toh
+#define HAVE_DECL_LE16TOH 1
+#endif
+
+#ifdef htobe32
+#define HAVE_DECL_HTOBE32 1
+#endif
+#ifdef htole32
+#define HAVE_DECL_HTOLE32 1
+#endif
+#ifdef be32toh
+#define HAVE_DECL_BE32TOH 1
+#endif
+#ifdef le32toh
+#define HAVE_DECL_LE32TOH 1
+#endif
+
+#ifdef htobe64
+#define HAVE_DECL_HTOBE64 1
+#endif
+#ifdef htole64
+#define HAVE_DECL_HTOLE64 1
+#endif
+#ifdef be64toh
+#define HAVE_DECL_BE64TOH 1
+#endif
+#ifdef le64toh
+#define HAVE_DECL_LE64TOH 1
+#endif
+
+#endif // HAVE_CONFIG_H
+
#if defined(WORDS_BIGENDIAN)
#if HAVE_DECL_HTOBE16 == 0
diff --git a/src/consensus/params.h b/src/consensus/params.h
index 4ef808c856..0559304fc2 100644
--- a/src/consensus/params.h
+++ b/src/consensus/params.h
@@ -49,8 +49,8 @@ struct BIP9Deployment {
struct Params {
uint256 hashGenesisBlock;
int nSubsidyHalvingInterval;
- /** Block height at which BIP16 becomes active */
- int BIP16Height;
+ /* Block hash that is excepted from BIP16 enforcement */
+ uint256 BIP16Exception;
/** Block height and hash at which BIP34 becomes active */
int BIP34Height;
uint256 BIP34Hash;
diff --git a/src/init.cpp b/src/init.cpp
index 8538630d7e..f403f90b08 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -684,7 +684,7 @@ void ThreadImport(std::vector<fs::path> vImportFiles)
// scan for better chains in the block chain database, that are not yet connected in the active best chain
CValidationState state;
if (!ActivateBestChain(state, chainparams)) {
- LogPrintf("Failed to connect best block\n");
+ LogPrintf("Failed to connect best block (%s)\n", FormatStateMessage(state));
StartShutdown();
return;
}
diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp
index ddd5496a80..e55cba3c65 100644
--- a/src/interfaces/node.cpp
+++ b/src/interfaces/node.cpp
@@ -236,7 +236,7 @@ class NodeImpl : public Node
{
#ifdef ENABLE_WALLET
std::vector<std::unique_ptr<Wallet>> wallets;
- for (CWalletRef wallet : ::vpwallets) {
+ for (CWallet* wallet : GetWallets()) {
wallets.emplace_back(MakeWallet(*wallet));
}
return wallets;
diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h
index dfe3d5f711..9d4830d189 100644
--- a/src/interfaces/wallet.h
+++ b/src/interfaces/wallet.h
@@ -6,7 +6,7 @@
#define BITCOIN_INTERFACES_WALLET_H
#include <amount.h> // For CAmount
-#include <pubkey.h> // For CTxDestination (CKeyID and CScriptID)
+#include <pubkey.h> // For CKeyID and CScriptID (definitions needed in CTxDestination instantiation)
#include <script/ismine.h> // For isminefilter, isminetype
#include <script/standard.h> // For CTxDestination
#include <support/allocators/secure.h> // For SecureString
diff --git a/src/logging.cpp b/src/logging.cpp
new file mode 100644
index 0000000000..e481582321
--- /dev/null
+++ b/src/logging.cpp
@@ -0,0 +1,283 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2018 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 <logging.h>
+#include <util.h>
+#include <utilstrencodings.h>
+
+#include <list>
+#include <mutex>
+
+const char * const DEFAULT_DEBUGLOGFILE = "debug.log";
+
+bool fPrintToConsole = false;
+bool fPrintToDebugLog = true;
+
+bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS;
+bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS;
+bool fLogIPs = DEFAULT_LOGIPS;
+std::atomic<bool> fReopenDebugLog(false);
+
+/** Log categories bitfield. */
+std::atomic<uint32_t> logCategories(0);
+/**
+ * LogPrintf() has been broken a couple of times now
+ * by well-meaning people adding mutexes in the most straightforward way.
+ * It breaks because it may be called by global destructors during shutdown.
+ * Since the order of destruction of static/global objects is undefined,
+ * defining a mutex as a global object doesn't work (the mutex gets
+ * destroyed, and then some later destructor calls OutputDebugStringF,
+ * maybe indirectly, and you get a core dump at shutdown trying to lock
+ * the mutex).
+ */
+
+static std::once_flag debugPrintInitFlag;
+
+/**
+ * We use std::call_once() to make sure mutexDebugLog and
+ * vMsgsBeforeOpenLog are initialized in a thread-safe manner.
+ *
+ * NOTE: fileout, mutexDebugLog and sometimes vMsgsBeforeOpenLog
+ * are leaked on exit. This is ugly, but will be cleaned up by
+ * the OS/libc. When the shutdown sequence is fully audited and
+ * tested, explicit destruction of these objects can be implemented.
+ */
+static FILE* fileout = nullptr;
+static std::mutex* mutexDebugLog = nullptr;
+static std::list<std::string>* vMsgsBeforeOpenLog;
+
+static int FileWriteStr(const std::string &str, FILE *fp)
+{
+ return fwrite(str.data(), 1, str.size(), fp);
+}
+
+static void DebugPrintInit()
+{
+ assert(mutexDebugLog == nullptr);
+ mutexDebugLog = new std::mutex();
+ vMsgsBeforeOpenLog = new std::list<std::string>;
+}
+
+fs::path GetDebugLogPath()
+{
+ fs::path logfile(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE));
+ return AbsPathForConfigVal(logfile);
+}
+
+bool OpenDebugLog()
+{
+ std::call_once(debugPrintInitFlag, &DebugPrintInit);
+ std::lock_guard<std::mutex> scoped_lock(*mutexDebugLog);
+
+ assert(fileout == nullptr);
+ assert(vMsgsBeforeOpenLog);
+ fs::path pathDebug = GetDebugLogPath();
+
+ fileout = fsbridge::fopen(pathDebug, "a");
+ if (!fileout) {
+ return false;
+ }
+
+ setbuf(fileout, nullptr); // unbuffered
+ // dump buffered messages from before we opened the log
+ while (!vMsgsBeforeOpenLog->empty()) {
+ FileWriteStr(vMsgsBeforeOpenLog->front(), fileout);
+ vMsgsBeforeOpenLog->pop_front();
+ }
+
+ delete vMsgsBeforeOpenLog;
+ vMsgsBeforeOpenLog = nullptr;
+ return true;
+}
+
+struct CLogCategoryDesc
+{
+ uint32_t flag;
+ std::string category;
+};
+
+const CLogCategoryDesc LogCategories[] =
+{
+ {BCLog::NONE, "0"},
+ {BCLog::NONE, "none"},
+ {BCLog::NET, "net"},
+ {BCLog::TOR, "tor"},
+ {BCLog::MEMPOOL, "mempool"},
+ {BCLog::HTTP, "http"},
+ {BCLog::BENCH, "bench"},
+ {BCLog::ZMQ, "zmq"},
+ {BCLog::DB, "db"},
+ {BCLog::RPC, "rpc"},
+ {BCLog::ESTIMATEFEE, "estimatefee"},
+ {BCLog::ADDRMAN, "addrman"},
+ {BCLog::SELECTCOINS, "selectcoins"},
+ {BCLog::REINDEX, "reindex"},
+ {BCLog::CMPCTBLOCK, "cmpctblock"},
+ {BCLog::RAND, "rand"},
+ {BCLog::PRUNE, "prune"},
+ {BCLog::PROXY, "proxy"},
+ {BCLog::MEMPOOLREJ, "mempoolrej"},
+ {BCLog::LIBEVENT, "libevent"},
+ {BCLog::COINDB, "coindb"},
+ {BCLog::QT, "qt"},
+ {BCLog::LEVELDB, "leveldb"},
+ {BCLog::ALL, "1"},
+ {BCLog::ALL, "all"},
+};
+
+bool GetLogCategory(uint32_t *f, const std::string *str)
+{
+ if (f && str) {
+ if (*str == "") {
+ *f = BCLog::ALL;
+ return true;
+ }
+ for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
+ if (LogCategories[i].category == *str) {
+ *f = LogCategories[i].flag;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+std::string ListLogCategories()
+{
+ std::string ret;
+ int outcount = 0;
+ for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
+ // Omit the special cases.
+ if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL) {
+ if (outcount != 0) ret += ", ";
+ ret += LogCategories[i].category;
+ outcount++;
+ }
+ }
+ return ret;
+}
+
+std::vector<CLogCategoryActive> ListActiveLogCategories()
+{
+ std::vector<CLogCategoryActive> ret;
+ for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
+ // Omit the special cases.
+ if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL) {
+ CLogCategoryActive catActive;
+ catActive.category = LogCategories[i].category;
+ catActive.active = LogAcceptCategory(LogCategories[i].flag);
+ ret.push_back(catActive);
+ }
+ }
+ return ret;
+}
+
+/**
+ * fStartedNewLine is a state variable held by the calling context that will
+ * suppress printing of the timestamp when multiple calls are made that don't
+ * end in a newline. Initialize it to true, and hold it, in the calling context.
+ */
+static std::string LogTimestampStr(const std::string &str, std::atomic_bool *fStartedNewLine)
+{
+ std::string strStamped;
+
+ if (!fLogTimestamps)
+ return str;
+
+ if (*fStartedNewLine) {
+ int64_t nTimeMicros = GetTimeMicros();
+ strStamped = FormatISO8601DateTime(nTimeMicros/1000000);
+ if (fLogTimeMicros) {
+ strStamped.pop_back();
+ strStamped += strprintf(".%06dZ", nTimeMicros%1000000);
+ }
+ int64_t mocktime = GetMockTime();
+ if (mocktime) {
+ strStamped += " (mocktime: " + FormatISO8601DateTime(mocktime) + ")";
+ }
+ strStamped += ' ' + str;
+ } else
+ strStamped = str;
+
+ if (!str.empty() && str[str.size()-1] == '\n')
+ *fStartedNewLine = true;
+ else
+ *fStartedNewLine = false;
+
+ return strStamped;
+}
+
+int LogPrintStr(const std::string &str)
+{
+ int ret = 0; // Returns total number of characters written
+ static std::atomic_bool fStartedNewLine(true);
+
+ std::string strTimestamped = LogTimestampStr(str, &fStartedNewLine);
+
+ if (fPrintToConsole) {
+ // print to console
+ ret = fwrite(strTimestamped.data(), 1, strTimestamped.size(), stdout);
+ fflush(stdout);
+ }
+ if (fPrintToDebugLog) {
+ std::call_once(debugPrintInitFlag, &DebugPrintInit);
+ std::lock_guard<std::mutex> scoped_lock(*mutexDebugLog);
+
+ // buffer if we haven't opened the log yet
+ if (fileout == nullptr) {
+ assert(vMsgsBeforeOpenLog);
+ ret = strTimestamped.length();
+ vMsgsBeforeOpenLog->push_back(strTimestamped);
+ }
+ else
+ {
+ // reopen the log file, if requested
+ if (fReopenDebugLog) {
+ fReopenDebugLog = false;
+ fs::path pathDebug = GetDebugLogPath();
+ if (fsbridge::freopen(pathDebug,"a",fileout) != nullptr)
+ setbuf(fileout, nullptr); // unbuffered
+ }
+
+ ret = FileWriteStr(strTimestamped, fileout);
+ }
+ }
+ return ret;
+}
+
+void ShrinkDebugFile()
+{
+ // Amount of debug.log to save at end when shrinking (must fit in memory)
+ constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000;
+ // Scroll debug.log if it's getting too big
+ fs::path pathLog = GetDebugLogPath();
+ FILE* file = fsbridge::fopen(pathLog, "r");
+
+ // Special files (e.g. device nodes) may not have a size.
+ size_t log_size = 0;
+ try {
+ log_size = fs::file_size(pathLog);
+ } catch (boost::filesystem::filesystem_error &) {}
+
+ // If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE
+ // trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes
+ if (file && log_size > 11 * (RECENT_DEBUG_HISTORY_SIZE / 10))
+ {
+ // Restart the file with some of the end
+ std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0);
+ fseek(file, -((long)vch.size()), SEEK_END);
+ int nBytes = fread(vch.data(), 1, vch.size(), file);
+ fclose(file);
+
+ file = fsbridge::fopen(pathLog, "w");
+ if (file)
+ {
+ fwrite(vch.data(), 1, nBytes, file);
+ fclose(file);
+ }
+ }
+ else if (file != nullptr)
+ fclose(file);
+}
diff --git a/src/logging.h b/src/logging.h
new file mode 100644
index 0000000000..4053f75acf
--- /dev/null
+++ b/src/logging.h
@@ -0,0 +1,125 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_LOGGING_H
+#define BITCOIN_LOGGING_H
+
+#include <fs.h>
+#include <tinyformat.h>
+
+#include <atomic>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+static const bool DEFAULT_LOGTIMEMICROS = false;
+static const bool DEFAULT_LOGIPS = false;
+static const bool DEFAULT_LOGTIMESTAMPS = true;
+extern const char * const DEFAULT_DEBUGLOGFILE;
+
+extern bool fPrintToConsole;
+extern bool fPrintToDebugLog;
+
+extern bool fLogTimestamps;
+extern bool fLogTimeMicros;
+extern bool fLogIPs;
+extern std::atomic<bool> fReopenDebugLog;
+
+extern std::atomic<uint32_t> logCategories;
+
+struct CLogCategoryActive
+{
+ std::string category;
+ bool active;
+};
+
+namespace BCLog {
+ enum LogFlags : uint32_t {
+ NONE = 0,
+ NET = (1 << 0),
+ TOR = (1 << 1),
+ MEMPOOL = (1 << 2),
+ HTTP = (1 << 3),
+ BENCH = (1 << 4),
+ ZMQ = (1 << 5),
+ DB = (1 << 6),
+ RPC = (1 << 7),
+ ESTIMATEFEE = (1 << 8),
+ ADDRMAN = (1 << 9),
+ SELECTCOINS = (1 << 10),
+ REINDEX = (1 << 11),
+ CMPCTBLOCK = (1 << 12),
+ RAND = (1 << 13),
+ PRUNE = (1 << 14),
+ PROXY = (1 << 15),
+ MEMPOOLREJ = (1 << 16),
+ LIBEVENT = (1 << 17),
+ COINDB = (1 << 18),
+ QT = (1 << 19),
+ LEVELDB = (1 << 20),
+ ALL = ~(uint32_t)0,
+ };
+}
+/** Return true if log accepts specified category */
+static inline bool LogAcceptCategory(uint32_t category)
+{
+ return (logCategories.load(std::memory_order_relaxed) & category) != 0;
+}
+
+/** Returns a string with the log categories. */
+std::string ListLogCategories();
+
+/** Returns a vector of the active log categories. */
+std::vector<CLogCategoryActive> ListActiveLogCategories();
+
+/** Return true if str parses as a log category and set the flags in f */
+bool GetLogCategory(uint32_t *f, const std::string *str);
+
+/** Send a string to the log output */
+int LogPrintStr(const std::string &str);
+
+/** Get format string from VA_ARGS for error reporting */
+template<typename... Args> std::string FormatStringFromLogArgs(const char *fmt, const Args&... args) { return fmt; }
+
+static inline void MarkUsed() {}
+template<typename T, typename... Args> static inline void MarkUsed(const T& t, const Args&... args)
+{
+ (void)t;
+ MarkUsed(args...);
+}
+
+// Be conservative when using LogPrintf/error or other things which
+// unconditionally log to debug.log! It should not be the case that an inbound
+// peer can fill up a user's disk with debug.log entries.
+
+#ifdef USE_COVERAGE
+#define LogPrintf(...) do { MarkUsed(__VA_ARGS__); } while(0)
+#define LogPrint(category, ...) do { MarkUsed(__VA_ARGS__); } while(0)
+#else
+#define LogPrintf(...) do { \
+ if (fPrintToConsole || fPrintToDebugLog) { \
+ std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \
+ try { \
+ _log_msg_ = tfm::format(__VA_ARGS__); \
+ } catch (tinyformat::format_error &fmterr) { \
+ /* Original format string will have newline so don't add one here */ \
+ _log_msg_ = "Error \"" + std::string(fmterr.what()) + "\" while formatting log message: " + FormatStringFromLogArgs(__VA_ARGS__); \
+ } \
+ LogPrintStr(_log_msg_); \
+ } \
+} while(0)
+
+#define LogPrint(category, ...) do { \
+ if (LogAcceptCategory((category))) { \
+ LogPrintf(__VA_ARGS__); \
+ } \
+} while(0)
+#endif
+
+fs::path GetDebugLogPath();
+bool OpenDebugLog();
+void ShrinkDebugFile();
+
+#endif // BITCOIN_LOGGING_H
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index dbdae705de..ee4e9e61bc 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -1100,8 +1100,10 @@ void static ProcessGetBlockData(CNode* pfrom, const Consensus::Params& consensus
}
} // release cs_main before calling ActivateBestChain
if (need_activate_chain) {
- CValidationState dummy;
- ActivateBestChain(dummy, Params(), a_recent_block);
+ CValidationState state;
+ if (!ActivateBestChain(state, Params(), a_recent_block)) {
+ LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state));
+ }
}
LOCK(cs_main);
@@ -1992,8 +1994,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
LOCK(cs_most_recent_block);
a_recent_block = most_recent_block;
}
- CValidationState dummy;
- ActivateBestChain(dummy, Params(), a_recent_block);
+ CValidationState state;
+ if (!ActivateBestChain(state, Params(), a_recent_block)) {
+ LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state));
+ }
}
LOCK(cs_main);
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index dcc834c352..56d2d38194 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -180,9 +180,9 @@ void TestGUI()
TransactionView transactionView(platformStyle.get());
auto node = interfaces::MakeNode();
OptionsModel optionsModel(*node);
- vpwallets.insert(vpwallets.begin(), &wallet);
- WalletModel walletModel(std::move(node->getWallets()[0]), *node, platformStyle.get(), &optionsModel);
- vpwallets.erase(vpwallets.begin());
+ AddWallet(&wallet);
+ WalletModel walletModel(std::move(node->getWallets().back()), *node, platformStyle.get(), &optionsModel);
+ RemoveWallet(&wallet);
sendCoinsDialog.setModel(&walletModel);
transactionView.setModel(&walletModel);
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 9a7c4b8e6d..b4bb78e689 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -116,7 +116,7 @@ UniValue generateBlocks(std::shared_ptr<CReserveScript> coinbaseScript, int nGen
}
unsigned int nExtraNonce = 0;
UniValue blockHashes(UniValue::VARR);
- while (nHeight < nHeightEnd)
+ while (nHeight < nHeightEnd && !ShutdownRequested())
{
std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(Params()).CreateNewBlock(coinbaseScript->reserveScript));
if (!pblocktemplate.get())
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 49e865a64a..6754407dbd 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -69,7 +69,7 @@ UniValue validateaddress(const JSONRPCRequest& request)
{
#ifdef ENABLE_WALLET
- if (!::vpwallets.empty() && IsDeprecatedRPCEnabled("validateaddress")) {
+ if (HasWallets() && IsDeprecatedRPCEnabled("validateaddress")) {
ret.pushKVs(getaddressinfo(request));
}
#endif
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index b72df1604f..e9873f4526 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -85,7 +85,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
{
CValidationState state;
if (!ActivateBestChain(state, chainparams)) {
- throw std::runtime_error("ActivateBestChain failed.");
+ throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", FormatStateMessage(state)));
}
}
nScriptCheckThreads = 3;
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 344113b60c..1c3acfb1a5 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -572,7 +572,7 @@ BOOST_AUTO_TEST_CASE(util_GetChainName)
BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
// check setting the network to test (and thus making
- // [test] regtest=1 potentially relevent) doesn't break things
+ // [test] regtest=1 potentially relevant) doesn't break things
test_args.SelectConfigNetwork("test");
test_args.ParseParameters(0, (char**)argv_testnet);
diff --git a/src/util.cpp b/src/util.cpp
index 6b0bffa35a..9a3067259f 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -84,21 +84,11 @@ const int64_t nStartupTime = GetTime();
const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf";
const char * const BITCOIN_PID_FILENAME = "bitcoind.pid";
-const char * const DEFAULT_DEBUGLOGFILE = "debug.log";
ArgsManager gArgs;
-bool fPrintToConsole = false;
-bool fPrintToDebugLog = true;
-bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS;
-bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS;
-bool fLogIPs = DEFAULT_LOGIPS;
-std::atomic<bool> fReopenDebugLog(false);
CTranslationInterface translationInterface;
-/** Log categories bitfield. */
-std::atomic<uint32_t> logCategories(0);
-
/** Init OpenSSL library multithreading support */
static std::unique_ptr<CCriticalSection[]> ppmutexOpenSSL;
void locking_callback(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS
@@ -147,231 +137,6 @@ public:
}
instance_of_cinit;
-/**
- * LogPrintf() has been broken a couple of times now
- * by well-meaning people adding mutexes in the most straightforward way.
- * It breaks because it may be called by global destructors during shutdown.
- * Since the order of destruction of static/global objects is undefined,
- * defining a mutex as a global object doesn't work (the mutex gets
- * destroyed, and then some later destructor calls OutputDebugStringF,
- * maybe indirectly, and you get a core dump at shutdown trying to lock
- * the mutex).
- */
-
-static std::once_flag debugPrintInitFlag;
-
-/**
- * We use std::call_once() to make sure mutexDebugLog and
- * vMsgsBeforeOpenLog are initialized in a thread-safe manner.
- *
- * NOTE: fileout, mutexDebugLog and sometimes vMsgsBeforeOpenLog
- * are leaked on exit. This is ugly, but will be cleaned up by
- * the OS/libc. When the shutdown sequence is fully audited and
- * tested, explicit destruction of these objects can be implemented.
- */
-static FILE* fileout = nullptr;
-static std::mutex* mutexDebugLog = nullptr;
-static std::list<std::string>* vMsgsBeforeOpenLog;
-
-static int FileWriteStr(const std::string &str, FILE *fp)
-{
- return fwrite(str.data(), 1, str.size(), fp);
-}
-
-static void DebugPrintInit()
-{
- assert(mutexDebugLog == nullptr);
- mutexDebugLog = new std::mutex();
- vMsgsBeforeOpenLog = new std::list<std::string>;
-}
-
-fs::path GetDebugLogPath()
-{
- fs::path logfile(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE));
- return AbsPathForConfigVal(logfile);
-}
-
-bool OpenDebugLog()
-{
- std::call_once(debugPrintInitFlag, &DebugPrintInit);
- std::lock_guard<std::mutex> scoped_lock(*mutexDebugLog);
-
- assert(fileout == nullptr);
- assert(vMsgsBeforeOpenLog);
- fs::path pathDebug = GetDebugLogPath();
-
- fileout = fsbridge::fopen(pathDebug, "a");
- if (!fileout) {
- return false;
- }
-
- setbuf(fileout, nullptr); // unbuffered
- // dump buffered messages from before we opened the log
- while (!vMsgsBeforeOpenLog->empty()) {
- FileWriteStr(vMsgsBeforeOpenLog->front(), fileout);
- vMsgsBeforeOpenLog->pop_front();
- }
-
- delete vMsgsBeforeOpenLog;
- vMsgsBeforeOpenLog = nullptr;
- return true;
-}
-
-struct CLogCategoryDesc
-{
- uint32_t flag;
- std::string category;
-};
-
-const CLogCategoryDesc LogCategories[] =
-{
- {BCLog::NONE, "0"},
- {BCLog::NONE, "none"},
- {BCLog::NET, "net"},
- {BCLog::TOR, "tor"},
- {BCLog::MEMPOOL, "mempool"},
- {BCLog::HTTP, "http"},
- {BCLog::BENCH, "bench"},
- {BCLog::ZMQ, "zmq"},
- {BCLog::DB, "db"},
- {BCLog::RPC, "rpc"},
- {BCLog::ESTIMATEFEE, "estimatefee"},
- {BCLog::ADDRMAN, "addrman"},
- {BCLog::SELECTCOINS, "selectcoins"},
- {BCLog::REINDEX, "reindex"},
- {BCLog::CMPCTBLOCK, "cmpctblock"},
- {BCLog::RAND, "rand"},
- {BCLog::PRUNE, "prune"},
- {BCLog::PROXY, "proxy"},
- {BCLog::MEMPOOLREJ, "mempoolrej"},
- {BCLog::LIBEVENT, "libevent"},
- {BCLog::COINDB, "coindb"},
- {BCLog::QT, "qt"},
- {BCLog::LEVELDB, "leveldb"},
- {BCLog::ALL, "1"},
- {BCLog::ALL, "all"},
-};
-
-bool GetLogCategory(uint32_t *f, const std::string *str)
-{
- if (f && str) {
- if (*str == "") {
- *f = BCLog::ALL;
- return true;
- }
- for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
- if (LogCategories[i].category == *str) {
- *f = LogCategories[i].flag;
- return true;
- }
- }
- }
- return false;
-}
-
-std::string ListLogCategories()
-{
- std::string ret;
- int outcount = 0;
- for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
- // Omit the special cases.
- if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL) {
- if (outcount != 0) ret += ", ";
- ret += LogCategories[i].category;
- outcount++;
- }
- }
- return ret;
-}
-
-std::vector<CLogCategoryActive> ListActiveLogCategories()
-{
- std::vector<CLogCategoryActive> ret;
- for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
- // Omit the special cases.
- if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL) {
- CLogCategoryActive catActive;
- catActive.category = LogCategories[i].category;
- catActive.active = LogAcceptCategory(LogCategories[i].flag);
- ret.push_back(catActive);
- }
- }
- return ret;
-}
-
-/**
- * fStartedNewLine is a state variable held by the calling context that will
- * suppress printing of the timestamp when multiple calls are made that don't
- * end in a newline. Initialize it to true, and hold it, in the calling context.
- */
-static std::string LogTimestampStr(const std::string &str, std::atomic_bool *fStartedNewLine)
-{
- std::string strStamped;
-
- if (!fLogTimestamps)
- return str;
-
- if (*fStartedNewLine) {
- int64_t nTimeMicros = GetTimeMicros();
- strStamped = FormatISO8601DateTime(nTimeMicros/1000000);
- if (fLogTimeMicros) {
- strStamped.pop_back();
- strStamped += strprintf(".%06dZ", nTimeMicros%1000000);
- }
- int64_t mocktime = GetMockTime();
- if (mocktime) {
- strStamped += " (mocktime: " + FormatISO8601DateTime(mocktime) + ")";
- }
- strStamped += ' ' + str;
- } else
- strStamped = str;
-
- if (!str.empty() && str[str.size()-1] == '\n')
- *fStartedNewLine = true;
- else
- *fStartedNewLine = false;
-
- return strStamped;
-}
-
-int LogPrintStr(const std::string &str)
-{
- int ret = 0; // Returns total number of characters written
- static std::atomic_bool fStartedNewLine(true);
-
- std::string strTimestamped = LogTimestampStr(str, &fStartedNewLine);
-
- if (fPrintToConsole) {
- // print to console
- ret = fwrite(strTimestamped.data(), 1, strTimestamped.size(), stdout);
- fflush(stdout);
- }
- if (fPrintToDebugLog) {
- std::call_once(debugPrintInitFlag, &DebugPrintInit);
- std::lock_guard<std::mutex> scoped_lock(*mutexDebugLog);
-
- // buffer if we haven't opened the log yet
- if (fileout == nullptr) {
- assert(vMsgsBeforeOpenLog);
- ret = strTimestamped.length();
- vMsgsBeforeOpenLog->push_back(strTimestamped);
- }
- else
- {
- // reopen the log file, if requested
- if (fReopenDebugLog) {
- fReopenDebugLog = false;
- fs::path pathDebug = GetDebugLogPath();
- if (fsbridge::freopen(pathDebug,"a",fileout) != nullptr)
- setbuf(fileout, nullptr); // unbuffered
- }
-
- ret = FileWriteStr(strTimestamped, fileout);
- }
- }
- return ret;
-}
-
/** A map that contains all the currently held directory locks. After
* successful locking, these will be held here until the global destructor
* cleans them up and thus automatically unlocks them, or ReleaseDirectoryLocks
@@ -1023,21 +788,37 @@ bool TryCreateDirectories(const fs::path& p)
return false;
}
-void FileCommit(FILE *file)
+bool FileCommit(FILE *file)
{
- fflush(file); // harmless if redundantly called
+ if (fflush(file) != 0) { // harmless if redundantly called
+ LogPrintf("%s: fflush failed: %d\n", __func__, errno);
+ return false;
+ }
#ifdef WIN32
HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
- FlushFileBuffers(hFile);
+ if (FlushFileBuffers(hFile) == 0) {
+ LogPrintf("%s: FlushFileBuffers failed: %d\n", __func__, GetLastError());
+ return false;
+ }
#else
#if defined(__linux__) || defined(__NetBSD__)
- fdatasync(fileno(file));
+ if (fdatasync(fileno(file)) != 0 && errno != EINVAL) { // Ignore EINVAL for filesystems that don't support sync
+ LogPrintf("%s: fdatasync failed: %d\n", __func__, errno);
+ return false;
+ }
#elif defined(__APPLE__) && defined(F_FULLFSYNC)
- fcntl(fileno(file), F_FULLFSYNC, 0);
+ if (fcntl(fileno(file), F_FULLFSYNC, 0) == -1) { // Manpage says "value other than -1" is returned on success
+ LogPrintf("%s: fcntl F_FULLFSYNC failed: %d\n", __func__, errno);
+ return false;
+ }
#else
- fsync(fileno(file));
+ if (fsync(fileno(file)) != 0 && errno != EINVAL) {
+ LogPrintf("%s: fsync failed: %d\n", __func__, errno);
+ return false;
+ }
#endif
#endif
+ return true;
}
bool TruncateFile(FILE *file, unsigned int length) {
@@ -1117,41 +898,6 @@ void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
#endif
}
-void ShrinkDebugFile()
-{
- // Amount of debug.log to save at end when shrinking (must fit in memory)
- constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000;
- // Scroll debug.log if it's getting too big
- fs::path pathLog = GetDebugLogPath();
- FILE* file = fsbridge::fopen(pathLog, "r");
-
- // Special files (e.g. device nodes) may not have a size.
- size_t log_size = 0;
- try {
- log_size = fs::file_size(pathLog);
- } catch (boost::filesystem::filesystem_error &) {}
-
- // If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE
- // trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes
- if (file && log_size > 11 * (RECENT_DEBUG_HISTORY_SIZE / 10))
- {
- // Restart the file with some of the end
- std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0);
- fseek(file, -((long)vch.size()), SEEK_END);
- int nBytes = fread(vch.data(), 1, vch.size(), file);
- fclose(file);
-
- file = fsbridge::fopen(pathLog, "w");
- if (file)
- {
- fwrite(vch.data(), 1, nBytes, file);
- fclose(file);
- }
- }
- else if (file != nullptr)
- fclose(file);
-}
-
#ifdef WIN32
fs::path GetSpecialFolderPath(int nFolder, bool fCreate)
{
diff --git a/src/util.h b/src/util.h
index ffdee99d27..ce94f396af 100644
--- a/src/util.h
+++ b/src/util.h
@@ -5,7 +5,7 @@
/**
* Server/client environment: argument handling, config file parsing,
- * logging, thread wrappers, startup time
+ * thread wrappers, startup time
*/
#ifndef BITCOIN_UTIL_H
#define BITCOIN_UTIL_H
@@ -16,6 +16,7 @@
#include <compat.h>
#include <fs.h>
+#include <logging.h>
#include <sync.h>
#include <tinyformat.h>
#include <utiltime.h>
@@ -36,11 +37,6 @@
// Application startup time (used for uptime calculation)
int64_t GetStartupTime();
-static const bool DEFAULT_LOGTIMEMICROS = false;
-static const bool DEFAULT_LOGIPS = false;
-static const bool DEFAULT_LOGTIMESTAMPS = true;
-extern const char * const DEFAULT_DEBUGLOGFILE;
-
/** Signals for translation. */
class CTranslationInterface
{
@@ -49,20 +45,11 @@ public:
boost::signals2::signal<std::string (const char* psz)> Translate;
};
-extern bool fPrintToConsole;
-extern bool fPrintToDebugLog;
-
-extern bool fLogTimestamps;
-extern bool fLogTimeMicros;
-extern bool fLogIPs;
-extern std::atomic<bool> fReopenDebugLog;
extern CTranslationInterface translationInterface;
extern const char * const BITCOIN_CONF_FILENAME;
extern const char * const BITCOIN_PID_FILENAME;
-extern std::atomic<uint32_t> logCategories;
-
/**
* Translation function: Call Translate signal on UI interface, which returns a boost::optional result.
* If no translation slot is registered, nothing is returned, and simply return the input.
@@ -76,95 +63,6 @@ inline std::string _(const char* psz)
void SetupEnvironment();
bool SetupNetworking();
-struct CLogCategoryActive
-{
- std::string category;
- bool active;
-};
-
-namespace BCLog {
- enum LogFlags : uint32_t {
- NONE = 0,
- NET = (1 << 0),
- TOR = (1 << 1),
- MEMPOOL = (1 << 2),
- HTTP = (1 << 3),
- BENCH = (1 << 4),
- ZMQ = (1 << 5),
- DB = (1 << 6),
- RPC = (1 << 7),
- ESTIMATEFEE = (1 << 8),
- ADDRMAN = (1 << 9),
- SELECTCOINS = (1 << 10),
- REINDEX = (1 << 11),
- CMPCTBLOCK = (1 << 12),
- RAND = (1 << 13),
- PRUNE = (1 << 14),
- PROXY = (1 << 15),
- MEMPOOLREJ = (1 << 16),
- LIBEVENT = (1 << 17),
- COINDB = (1 << 18),
- QT = (1 << 19),
- LEVELDB = (1 << 20),
- ALL = ~(uint32_t)0,
- };
-}
-/** Return true if log accepts specified category */
-static inline bool LogAcceptCategory(uint32_t category)
-{
- return (logCategories.load(std::memory_order_relaxed) & category) != 0;
-}
-
-/** Returns a string with the log categories. */
-std::string ListLogCategories();
-
-/** Returns a vector of the active log categories. */
-std::vector<CLogCategoryActive> ListActiveLogCategories();
-
-/** Return true if str parses as a log category and set the flags in f */
-bool GetLogCategory(uint32_t *f, const std::string *str);
-
-/** Send a string to the log output */
-int LogPrintStr(const std::string &str);
-
-/** Get format string from VA_ARGS for error reporting */
-template<typename... Args> std::string FormatStringFromLogArgs(const char *fmt, const Args&... args) { return fmt; }
-
-static inline void MarkUsed() {}
-template<typename T, typename... Args> static inline void MarkUsed(const T& t, const Args&... args)
-{
- (void)t;
- MarkUsed(args...);
-}
-
-// Be conservative when using LogPrintf/error or other things which
-// unconditionally log to debug.log! It should not be the case that an inbound
-// peer can fill up a user's disk with debug.log entries.
-
-#ifdef USE_COVERAGE
-#define LogPrintf(...) do { MarkUsed(__VA_ARGS__); } while(0)
-#define LogPrint(category, ...) do { MarkUsed(__VA_ARGS__); } while(0)
-#else
-#define LogPrintf(...) do { \
- if (fPrintToConsole || fPrintToDebugLog) { \
- std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \
- try { \
- _log_msg_ = tfm::format(__VA_ARGS__); \
- } catch (tinyformat::format_error &fmterr) { \
- /* Original format string will have newline so don't add one here */ \
- _log_msg_ = "Error \"" + std::string(fmterr.what()) + "\" while formatting log message: " + FormatStringFromLogArgs(__VA_ARGS__); \
- } \
- LogPrintStr(_log_msg_); \
- } \
-} while(0)
-
-#define LogPrint(category, ...) do { \
- if (LogAcceptCategory((category))) { \
- LogPrintf(__VA_ARGS__); \
- } \
-} while(0)
-#endif
-
template<typename... Args>
bool error(const char* fmt, const Args&... args)
{
@@ -173,7 +71,7 @@ bool error(const char* fmt, const Args&... args)
}
void PrintExceptionContinue(const std::exception *pex, const char* pszThread);
-void FileCommit(FILE *file);
+bool FileCommit(FILE *file);
bool TruncateFile(FILE *file, unsigned int length);
int RaiseFileDescriptorLimit(int nMinFD);
void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length);
@@ -199,9 +97,6 @@ void CreatePidFile(const fs::path &path, pid_t pid);
#ifdef WIN32
fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
#endif
-fs::path GetDebugLogPath();
-bool OpenDebugLog();
-void ShrinkDebugFile();
void runCommand(const std::string& strCommand);
/**
diff --git a/src/validation.cpp b/src/validation.cpp
index 3726cb3b14..ab44e73d7c 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -142,7 +142,7 @@ private:
* ahead and mark descendants of invalid blocks as FAILED_CHILD at that time,
* instead of putting things in this set.
*/
- std::set<CBlockIndex*> g_failed_blocks;
+ std::set<CBlockIndex*> m_failed_blocks;
public:
CChain chainActive;
@@ -154,6 +154,10 @@ public:
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock);
+ /**
+ * If a block header hasn't already been seen, call CheckBlockHeader on it, ensure
+ * that it doesn't descend from an invalid block, and then add it to mapBlockIndex.
+ */
bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex);
bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, bool* fNewBlock);
@@ -185,6 +189,11 @@ private:
CBlockIndex* AddToBlockIndex(const CBlockHeader& block);
/** Create a new block index entry for a given block hash */
CBlockIndex * InsertBlockIndex(const uint256& hash);
+ /**
+ * Make various assertions about the state of the block index.
+ *
+ * By default this only executes fully when using the Regtest chain; see: fCheckBlockIndex.
+ */
void CheckBlockIndex(const Consensus::Params& consensusParams);
void InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state);
@@ -1286,7 +1295,7 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
void CChainState::InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) {
if (!state.CorruptionPossible()) {
pindex->nStatus |= BLOCK_FAILED_VALID;
- g_failed_blocks.insert(pindex);
+ m_failed_blocks.insert(pindex);
setDirtyBlockIndex.insert(pindex);
setBlockIndexCandidates.erase(pindex);
InvalidChainFound(pindex);
@@ -1615,22 +1624,27 @@ void static FlushBlockFile(bool fFinalize = false)
LOCK(cs_LastBlockFile);
CDiskBlockPos posOld(nLastBlockFile, 0);
+ bool status = true;
FILE *fileOld = OpenBlockFile(posOld);
if (fileOld) {
if (fFinalize)
- TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nSize);
- FileCommit(fileOld);
+ status &= TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nSize);
+ status &= FileCommit(fileOld);
fclose(fileOld);
}
fileOld = OpenUndoFile(posOld);
if (fileOld) {
if (fFinalize)
- TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nUndoSize);
- FileCommit(fileOld);
+ status &= TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nUndoSize);
+ status &= FileCommit(fileOld);
fclose(fileOld);
}
+
+ if (!status) {
+ AbortNode("Flushing block file to disk failed. This is likely the result of an I/O error.");
+ }
}
static bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize);
@@ -1726,16 +1740,38 @@ public:
// Protected by cs_main
static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS];
+// 0.13.0 was shipped with a segwit deployment defined for testnet, but not for
+// mainnet. We no longer need to support disabling the segwit deployment
+// except for testing purposes, due to limitations of the functional test
+// environment. See test/functional/p2p-segwit.py.
+static bool IsScriptWitnessEnabled(const Consensus::Params& params)
+{
+ return params.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout != 0;
+}
+
static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& consensusparams) {
AssertLockHeld(cs_main);
unsigned int flags = SCRIPT_VERIFY_NONE;
- // Start enforcing P2SH (BIP16)
- if (pindex->nHeight >= consensusparams.BIP16Height) {
+ // BIP16 didn't become active until Apr 1 2012 (on mainnet, and
+ // retroactively applied to testnet)
+ // However, only one historical block violated the P2SH rules (on both
+ // mainnet and testnet), so for simplicity, always leave P2SH
+ // on except for the one violating block.
+ if (consensusparams.BIP16Exception.IsNull() || // no bip16 exception on this chain
+ pindex->phashBlock == nullptr || // this is a new candidate block, eg from TestBlockValidity()
+ *pindex->phashBlock != consensusparams.BIP16Exception) // this block isn't the historical exception
+ {
flags |= SCRIPT_VERIFY_P2SH;
}
+ // Enforce WITNESS rules whenever P2SH is in effect (and the segwit
+ // deployment is defined).
+ if (flags & SCRIPT_VERIFY_P2SH && IsScriptWitnessEnabled(consensusparams)) {
+ flags |= SCRIPT_VERIFY_WITNESS;
+ }
+
// Start enforcing the DERSIG (BIP66) rule
if (pindex->nHeight >= consensusparams.BIP66Height) {
flags |= SCRIPT_VERIFY_DERSIG;
@@ -1751,9 +1787,7 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consens
flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY;
}
- // Start enforcing WITNESS rules using versionbits logic.
- if (IsWitnessEnabled(pindex->pprev, consensusparams)) {
- flags |= SCRIPT_VERIFY_WITNESS;
+ if (IsNullDummyEnabled(pindex->pprev, consensusparams)) {
flags |= SCRIPT_VERIFY_NULLDUMMY;
}
@@ -2181,14 +2215,18 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
void FlushStateToDisk() {
CValidationState state;
const CChainParams& chainparams = Params();
- FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS);
+ if (!FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS)) {
+ LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state));
+ }
}
void PruneAndFlush() {
CValidationState state;
fCheckForPruning = true;
const CChainParams& chainparams = Params();
- FlushStateToDisk(chainparams, state, FlushStateMode::NONE);
+ if (!FlushStateToDisk(chainparams, state, FlushStateMode::NONE)) {
+ LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state));
+ }
}
static void DoWarning(const std::string& strWarning)
@@ -2625,6 +2663,10 @@ static void NotifyHeaderTip() {
* Make the best chain active, in multiple steps. The result is either failure
* or an activated best chain. pblock is either nullptr or a pointer to a block
* that is already loaded (to avoid loading it again from disk).
+ *
+ * ActivateBestChain is split into steps (see ActivateBestChainStep) so that
+ * we avoid holding cs_main for an extended period of time; the length of this
+ * call may be quite long during reindexing or a substantial reorg.
*/
bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
// Note that while we're often called here from ProcessNewBlock, this is
@@ -2783,7 +2825,7 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c
pindex->nStatus |= BLOCK_FAILED_VALID;
setDirtyBlockIndex.insert(pindex);
setBlockIndexCandidates.erase(pindex);
- g_failed_blocks.insert(pindex);
+ m_failed_blocks.insert(pindex);
// DisconnectTip will add transactions to disconnectpool; try to add these
// back to the mempool.
@@ -2829,7 +2871,7 @@ bool CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
// Reset invalid block marker if it was pointing to one of those.
pindexBestInvalid = nullptr;
}
- g_failed_blocks.erase(it->second);
+ m_failed_blocks.erase(it->second);
}
it++;
}
@@ -3099,6 +3141,12 @@ bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& pa
return (VersionBitsState(pindexPrev, params, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == ThresholdState::ACTIVE);
}
+bool IsNullDummyEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params)
+{
+ LOCK(cs_main);
+ return (VersionBitsState(pindexPrev, params, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == ThresholdState::ACTIVE);
+}
+
// Compute at which vout of the block's coinbase transaction the witness
// commitment occurs, or -1 if not found.
static int GetWitnessCommitmentIndex(const CBlock& block)
@@ -3322,8 +3370,11 @@ bool CChainState::AcceptBlockHeader(const CBlockHeader& block, CValidationState&
if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev, GetAdjustedTime()))
return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state));
+ // If the previous block index isn't valid, determine if it descends from any block which
+ // has been found invalid (g_failed_blocks), then mark pindexPrev and any blocks
+ // between them as failed.
if (!pindexPrev->IsValid(BLOCK_VALID_SCRIPTS)) {
- for (const CBlockIndex* failedit : g_failed_blocks) {
+ for (const CBlockIndex* failedit : m_failed_blocks) {
if (pindexPrev->GetAncestor(failedit->nHeight) == failedit) {
assert(failedit->nStatus & BLOCK_FAILED_VALID);
CBlockIndex* invalid_walk = pindexPrev;
@@ -3489,7 +3540,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
}
if (!ret) {
GetMainSignals().BlockChecked(*pblock, state);
- return error("%s: AcceptBlock FAILED (%s)", __func__, state.GetDebugMessage());
+ return error("%s: AcceptBlock FAILED (%s)", __func__, FormatStateMessage(state));
}
}
@@ -3497,7 +3548,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
CValidationState state; // Only used to report errors, not invalidity - ignore it
if (!g_chainstate.ActivateBestChain(state, chainparams, pblock))
- return error("%s: ActivateBestChain failed", __func__);
+ return error("%s: ActivateBestChain failed (%s)", __func__, FormatStateMessage(state));
return true;
}
@@ -3615,7 +3666,9 @@ void PruneBlockFilesManual(int nManualPruneHeight)
{
CValidationState state;
const CChainParams& chainparams = Params();
- FlushStateToDisk(chainparams, state, FlushStateMode::NONE, nManualPruneHeight);
+ if (!FlushStateToDisk(chainparams, state, FlushStateMode::NONE, nManualPruneHeight)) {
+ LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state));
+ }
}
/**
@@ -3869,6 +3922,7 @@ bool LoadChainTip(const CChainParams& chainparams)
LogPrintf("%s: Connecting genesis block...\n", __func__);
CValidationState state;
if (!ActivateBestChain(state, chainparams)) {
+ LogPrintf("%s: failed to activate chain (%s)\n", __func__, FormatStateMessage(state));
return false;
}
}
@@ -3983,7 +4037,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus()))
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
if (!g_chainstate.ConnectBlock(block, state, pindex, coins, chainparams))
- return error("VerifyDB(): *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
+ return error("VerifyDB(): *** found unconnectable block at %d, hash=%s (%s)", pindex->nHeight, pindex->GetBlockHash().ToString(), FormatStateMessage(state));
}
}
@@ -4091,6 +4145,9 @@ bool CChainState::RewindBlockIndex(const CChainParams& params)
int nHeight = 1;
while (nHeight <= chainActive.Height()) {
+ // Although SCRIPT_VERIFY_WITNESS is now generally enforced on all
+ // blocks in ConnectBlock, we don't need to go back and
+ // re-download/re-verify blocks from before segwit actually activated.
if (IsWitnessEnabled(chainActive[nHeight - 1], params.GetConsensus()) && !(chainActive[nHeight]->nStatus & BLOCK_OPT_WITNESS)) {
break;
}
@@ -4110,11 +4167,13 @@ bool CChainState::RewindBlockIndex(const CChainParams& params)
break;
}
if (!DisconnectTip(state, params, nullptr)) {
- return error("RewindBlockIndex: unable to disconnect block at height %i", pindex->nHeight);
+ return error("RewindBlockIndex: unable to disconnect block at height %i (%s)", pindex->nHeight, FormatStateMessage(state));
}
// Occasionally flush state to disk.
- if (!FlushStateToDisk(params, state, FlushStateMode::PERIODIC))
+ if (!FlushStateToDisk(params, state, FlushStateMode::PERIODIC)) {
+ LogPrintf("RewindBlockIndex: unable to flush state to disk (%s)\n", FormatStateMessage(state));
return false;
+ }
}
// Reduce validity flag and have-data flags.
@@ -4180,6 +4239,7 @@ bool RewindBlockIndex(const CChainParams& params) {
// it'll get called a bunch real soon.
CValidationState state;
if (!FlushStateToDisk(params, state, FlushStateMode::ALWAYS)) {
+ LogPrintf("RewindBlockIndex: unable to flush state to disk (%s)\n", FormatStateMessage(state));
return false;
}
}
@@ -4189,7 +4249,7 @@ bool RewindBlockIndex(const CChainParams& params) {
void CChainState::UnloadBlockIndex() {
nBlockSequenceId = 1;
- g_failed_blocks.clear();
+ m_failed_blocks.clear();
setBlockIndexCandidates.clear();
}
@@ -4266,7 +4326,7 @@ bool CChainState::LoadGenesisBlock(const CChainParams& chainparams)
CBlockIndex *pindex = AddToBlockIndex(block);
CValidationState state;
if (!ReceivedBlockTransactions(block, state, pindex, blockPos, chainparams.GetConsensus()))
- return error("%s: genesis block not accepted", __func__);
+ return error("%s: genesis block not accepted (%s)", __func__, FormatStateMessage(state));
} catch (const std::runtime_error& e) {
return error("%s: failed to write genesis block: %s", __func__, e.what());
}
@@ -4731,7 +4791,8 @@ bool DumpMempool(void)
}
file << mapDeltas;
- FileCommit(file.Get());
+ if (!FileCommit(file.Get()))
+ throw std::runtime_error("FileCommit failed");
file.fclose();
RenameOver(GetDataDir() / "mempool.dat.new", GetDataDir() / "mempool.dat");
int64_t last = GetTimeMicros();
diff --git a/src/validation.h b/src/validation.h
index 3668484696..b415a85053 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -411,6 +411,9 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
/** Check whether witness commitments are required for block. */
bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params);
+/** Check whether NULLDUMMY (BIP 147) has activated. */
+bool IsNullDummyEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params);
+
/** When there are blocks in the active chain with missing data, rewind the chainstate and remove them from the block index */
bool RewindBlockIndex(const CChainParams& params);
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index accfd6e149..5091477dfd 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -315,7 +315,7 @@ bool WalletInit::Open() const
if (!pwallet) {
return false;
}
- vpwallets.push_back(pwallet);
+ AddWallet(pwallet);
}
return true;
@@ -323,29 +323,29 @@ bool WalletInit::Open() const
void WalletInit::Start(CScheduler& scheduler) const
{
- for (CWalletRef pwallet : vpwallets) {
+ for (CWallet* pwallet : GetWallets()) {
pwallet->postInitProcess(scheduler);
}
}
void WalletInit::Flush() const
{
- for (CWalletRef pwallet : vpwallets) {
+ for (CWallet* pwallet : GetWallets()) {
pwallet->Flush(false);
}
}
void WalletInit::Stop() const
{
- for (CWalletRef pwallet : vpwallets) {
+ for (CWallet* pwallet : GetWallets()) {
pwallet->Flush(true);
}
}
void WalletInit::Close() const
{
- for (CWalletRef pwallet : vpwallets) {
+ for (CWallet* pwallet : GetWallets()) {
+ RemoveWallet(pwallet);
delete pwallet;
}
- vpwallets.clear();
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 56bdc0695c..9b5fb0b062 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -46,14 +46,13 @@ CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
if (request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
// wallet endpoint was used
std::string requestedWallet = urlDecode(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
- for (CWalletRef pwallet : ::vpwallets) {
- if (pwallet->GetName() == requestedWallet) {
- return pwallet;
- }
- }
- throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
+ CWallet* pwallet = GetWallet(requestedWallet);
+ if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
+ return pwallet;
}
- return ::vpwallets.size() == 1 || (request.fHelp && ::vpwallets.size() > 0) ? ::vpwallets[0] : nullptr;
+
+ std::vector<CWallet*> wallets = GetWallets();
+ return wallets.size() == 1 || (request.fHelp && wallets.size() > 0) ? wallets[0] : nullptr;
}
std::string HelpRequiringPassphrase(CWallet * const pwallet)
@@ -67,7 +66,7 @@ bool EnsureWalletIsAvailable(CWallet * const pwallet, bool avoidException)
{
if (pwallet) return true;
if (avoidException) return false;
- if (::vpwallets.empty()) {
+ if (!HasWallets()) {
// Note: It isn't currently possible to trigger this error because
// wallet RPC methods aren't registered unless a wallet is loaded. But
// this error is being kept as a precaution, because it's possible in
@@ -2862,8 +2861,7 @@ UniValue listwallets(const JSONRPCRequest& request)
UniValue obj(UniValue::VARR);
- for (CWalletRef pwallet : vpwallets) {
-
+ for (CWallet* pwallet : GetWallets()) {
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 57705926a3..99c963a348 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -74,7 +74,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
// after.
{
CWallet wallet("dummy", WalletDatabase::CreateDummy());
- vpwallets.insert(vpwallets.begin(), &wallet);
+ AddWallet(&wallet);
UniValue keys;
keys.setArray();
UniValue key;
@@ -105,7 +105,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
"downloading and rescanning the relevant blocks (see -reindex and -rescan "
"options).\"}},{\"success\":true}]",
0, oldTip->GetBlockTimeMax(), TIMESTAMP_WINDOW));
- vpwallets.erase(vpwallets.begin());
+ RemoveWallet(&wallet);
}
}
@@ -140,9 +140,9 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
JSONRPCRequest request;
request.params.setArray();
request.params.push_back((pathTemp / "wallet.backup").string());
- vpwallets.insert(vpwallets.begin(), &wallet);
+ AddWallet(&wallet);
::dumpwallet(request);
- vpwallets.erase(vpwallets.begin());
+ RemoveWallet(&wallet);
}
// Call importwallet RPC and verify all blocks with timestamps >= BLOCK_TIME
@@ -153,9 +153,9 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
JSONRPCRequest request;
request.params.setArray();
request.params.push_back((pathTemp / "wallet.backup").string());
- vpwallets.insert(vpwallets.begin(), &wallet);
+ AddWallet(&wallet);
::importwallet(request);
- vpwallets.erase(vpwallets.begin());
+ RemoveWallet(&wallet);
LOCK(wallet.cs_wallet);
BOOST_CHECK_EQUAL(wallet.mapWallet.size(), 3U);
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 45c85a7912..8c392434fc 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -28,12 +28,50 @@
#include <utilmoneystr.h>
#include <wallet/fees.h>
+#include <algorithm>
#include <assert.h>
#include <future>
#include <boost/algorithm/string/replace.hpp>
-std::vector<CWalletRef> vpwallets;
+static std::vector<CWallet*> vpwallets;
+
+bool AddWallet(CWallet* wallet)
+{
+ assert(wallet);
+ std::vector<CWallet*>::const_iterator i = std::find(vpwallets.begin(), vpwallets.end(), wallet);
+ if (i != vpwallets.end()) return false;
+ vpwallets.push_back(wallet);
+ return true;
+}
+
+bool RemoveWallet(CWallet* wallet)
+{
+ assert(wallet);
+ std::vector<CWallet*>::iterator i = std::find(vpwallets.begin(), vpwallets.end(), wallet);
+ if (i == vpwallets.end()) return false;
+ vpwallets.erase(i);
+ return true;
+}
+
+bool HasWallets()
+{
+ return !vpwallets.empty();
+}
+
+std::vector<CWallet*> GetWallets()
+{
+ return vpwallets;
+}
+
+CWallet* GetWallet(const std::string& name)
+{
+ for (CWallet* wallet : vpwallets) {
+ if (wallet->GetName() == name) return wallet;
+ }
+ return nullptr;
+}
+
/** Transaction fee set by the user */
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index b85f374a06..dd165de825 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -32,8 +32,11 @@
#include <utility>
#include <vector>
-typedef CWallet* CWalletRef;
-extern std::vector<CWalletRef> vpwallets;
+bool AddWallet(CWallet* wallet);
+bool RemoveWallet(CWallet* wallet);
+bool HasWallets();
+std::vector<CWallet*> GetWallets();
+CWallet* GetWallet(const std::string& name);
/**
* Settings
@@ -268,7 +271,7 @@ public:
//Get the marginal bytes of spending the specified output
int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* pwallet);
-/**
+/**
* A transaction with a bunch of additional info that only the owner cares about.
* It includes any unrecorded transactions needed to link it back to the block chain.
*/
@@ -653,7 +656,7 @@ struct CoinEligibilityFilter
};
class WalletRescanReserver; //forward declarations for ScanForWalletTransactions/RescanFromTime
-/**
+/**
* A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
* and provides the ability to create new transactions.
*/
@@ -903,7 +906,7 @@ public:
void GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) const;
unsigned int ComputeTimeSmart(const CWalletTx& wtx) const;
- /**
+ /**
* Increment the next transaction order id
* @return next transaction order id
*/
@@ -1032,7 +1035,7 @@ public:
}
void GetScriptForMining(std::shared_ptr<CReserveScript> &script);
-
+
unsigned int GetKeyPoolSize()
{
AssertLockHeld(cs_wallet); // set{Ex,In}ternalKeyPool
@@ -1057,7 +1060,7 @@ public:
//! Flush wallet (bitdb flush)
void Flush(bool shutdown=false);
- /**
+ /**
* Address book entry changed.
* @note called with lock cs_wallet held.
*/
@@ -1066,7 +1069,7 @@ public:
const std::string &purpose,
ChangeType status)> NotifyAddressBookChanged;
- /**
+ /**
* Wallet transaction added, removed or updated.
* @note called with lock cs_wallet held.
*/
@@ -1113,7 +1116,7 @@ public:
/* Generates a new HD master key (will not be activated) */
CPubKey GenerateNewHDMasterKey();
-
+
/* Set the current HD master key (will reset the chain child index counters)
Sets the master key's version based on the current wallet version (so the
caller must ensure the current wallet version is correct before calling
@@ -1184,7 +1187,7 @@ public:
};
-/**
+/**
* DEPRECATED Account information.
* Stored in wallet with key "acc"+string account name.
*/
@@ -1230,10 +1233,10 @@ std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key);
class WalletRescanReserver
{
private:
- CWalletRef m_wallet;
+ CWallet* m_wallet;
bool m_could_reserve;
public:
- explicit WalletRescanReserver(CWalletRef w) : m_wallet(w), m_could_reserve(false) {}
+ explicit WalletRescanReserver(CWallet* w) : m_wallet(w), m_could_reserve(false) {}
bool reserve()
{
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index bcc7cf877d..5b275131af 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -756,7 +756,7 @@ void MaybeCompactWalletDB()
return;
}
- for (CWalletRef pwallet : vpwallets) {
+ for (CWallet* pwallet : GetWallets()) {
WalletDatabase& dbh = pwallet->GetDBHandle();
unsigned int nUpdateCounter = dbh.nUpdateCounter;