aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/.clang-format5
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile.bench.include2
-rw-r--r--src/bench/bench.cpp4
-rw-r--r--src/bench/mempool_eviction.cpp2
-rw-r--r--src/bench/perf.cpp53
-rw-r--r--src/bench/perf.h37
-rw-r--r--src/bench/verify_script.cpp2
-rw-r--r--src/bitcoind.cpp5
-rw-r--r--src/chainparams.cpp6
-rw-r--r--src/chainparamsbase.cpp1
-rw-r--r--src/compat.h6
-rw-r--r--src/consensus/params.h4
-rw-r--r--src/core_write.cpp1
-rw-r--r--src/init.cpp70
-rw-r--r--src/init.h2
-rw-r--r--src/interfaces/node.cpp3
-rw-r--r--src/interfaces/node.h9
-rw-r--r--src/interfaces/wallet.h2
-rw-r--r--src/logging.cpp283
-rw-r--r--src/logging.h125
-rw-r--r--src/net.cpp27
-rw-r--r--src/netaddress.cpp50
-rw-r--r--src/netaddress.h10
-rw-r--r--src/netbase.cpp6
-rw-r--r--src/rpc/rawtransaction.cpp2
-rw-r--r--src/test/blockencodings_tests.cpp23
-rw-r--r--src/test/multisig_tests.cpp2
-rw-r--r--src/test/script_tests.cpp4
-rw-r--r--src/test/serialize_tests.cpp7
-rw-r--r--src/test/test_bitcoin.cpp10
-rw-r--r--src/test/test_bitcoin.h6
-rw-r--r--src/test/txvalidationcache_tests.cpp4
-rw-r--r--src/test/util_tests.cpp252
-rw-r--r--src/util.cpp544
-rw-r--r--src/util.h139
-rw-r--r--src/validation.cpp58
-rw-r--r--src/validation.h3
-rw-r--r--src/validationinterface.cpp4
-rw-r--r--src/wallet/init.cpp39
-rw-r--r--src/wallet/test/wallet_tests.cpp19
-rw-r--r--src/walletinitinterface.h18
42 files changed, 1072 insertions, 779 deletions
diff --git a/src/.clang-format b/src/.clang-format
index 2d2ee67035..38e19edf2c 100644
--- a/src/.clang-format
+++ b/src/.clang-format
@@ -12,7 +12,10 @@ AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackParameters: false
BreakBeforeBinaryOperators: false
-BreakBeforeBraces: Linux
+BreakBeforeBraces: Custom
+BraceWrapping:
+ AfterClass: true
+ AfterFunction: true
BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: false
ColumnLimit: 0
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/Makefile.bench.include b/src/Makefile.bench.include
index 748c5b7887..3306dcf598 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -25,8 +25,6 @@ bench_bench_bitcoin_SOURCES = \
bench/verify_script.cpp \
bench/base58.cpp \
bench/lockedpool.cpp \
- bench/perf.cpp \
- bench/perf.h \
bench/prevector.cpp
nodist_bench_bench_bitcoin_SOURCES = $(GENERATED_BENCH_FILES)
diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp
index 21329a5151..de3e57b04f 100644
--- a/src/bench/bench.cpp
+++ b/src/bench/bench.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bench/bench.h>
-#include <bench/perf.h>
#include <assert.h>
#include <iostream>
@@ -96,7 +95,6 @@ benchmark::BenchRunner::BenchRunner(std::string name, benchmark::BenchFunction f
void benchmark::BenchRunner::RunAll(Printer& printer, uint64_t num_evals, double scaling, const std::string& filter, bool is_list_only)
{
- perf_init();
if (!std::ratio_less_equal<benchmark::clock::period, std::micro>::value) {
std::cerr << "WARNING: Clock precision is worse than microsecond - benchmarks may be less accurate!\n";
}
@@ -126,8 +124,6 @@ void benchmark::BenchRunner::RunAll(Printer& printer, uint64_t num_evals, double
}
printer.footer();
-
- perf_fini();
}
bool benchmark::State::UpdateTimer(const benchmark::time_point current_time)
diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp
index cdda0bd9be..e05a5e3d1e 100644
--- a/src/bench/mempool_eviction.cpp
+++ b/src/bench/mempool_eviction.cpp
@@ -9,7 +9,7 @@
#include <list>
#include <vector>
-static void AddTx(const CTransaction& tx, const CAmount& nFee, CTxMemPool& pool)
+static void AddTx(const CMutableTransaction& tx, const CAmount& nFee, CTxMemPool& pool)
{
int64_t nTime = 0;
unsigned int nHeight = 1;
diff --git a/src/bench/perf.cpp b/src/bench/perf.cpp
deleted file mode 100644
index f92d08c56e..0000000000
--- a/src/bench/perf.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2016-2017 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 <bench/perf.h>
-
-#if defined(__i386__) || defined(__x86_64__)
-
-/* These architectures support querying the cycle counter
- * from user space, no need for any syscall overhead.
- */
-void perf_init(void) { }
-void perf_fini(void) { }
-
-#elif defined(__linux__)
-
-#include <unistd.h>
-#include <sys/syscall.h>
-#include <linux/perf_event.h>
-
-static int fd = -1;
-static struct perf_event_attr attr;
-
-void perf_init(void)
-{
- attr.type = PERF_TYPE_HARDWARE;
- attr.config = PERF_COUNT_HW_CPU_CYCLES;
- fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0);
-}
-
-void perf_fini(void)
-{
- if (fd != -1) {
- close(fd);
- }
-}
-
-uint64_t perf_cpucycles(void)
-{
- uint64_t result = 0;
- if (fd == -1 || read(fd, &result, sizeof(result)) < (ssize_t)sizeof(result)) {
- return 0;
- }
- return result;
-}
-
-#else /* Unhandled platform */
-
-void perf_init(void) { }
-void perf_fini(void) { }
-uint64_t perf_cpucycles(void) { return 0; }
-
-#endif
diff --git a/src/bench/perf.h b/src/bench/perf.h
deleted file mode 100644
index 73ea8b9647..0000000000
--- a/src/bench/perf.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 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.
-
-/** Functions for measurement of CPU cycles */
-#ifndef BITCOIN_BENCH_PERF_H
-#define BITCOIN_BENCH_PERF_H
-
-#include <stdint.h>
-
-#if defined(__i386__)
-
-static inline uint64_t perf_cpucycles(void)
-{
- uint64_t x;
- __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
- return x;
-}
-
-#elif defined(__x86_64__)
-
-static inline uint64_t perf_cpucycles(void)
-{
- uint32_t hi, lo;
- __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
- return ((uint64_t)lo)|(((uint64_t)hi)<<32);
-}
-#else
-
-uint64_t perf_cpucycles(void);
-
-#endif
-
-void perf_init(void);
-void perf_fini(void);
-
-#endif // BITCOIN_BENCH_PERF_H
diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp
index 705fa368a5..4100519d48 100644
--- a/src/bench/verify_script.cpp
+++ b/src/bench/verify_script.cpp
@@ -71,7 +71,7 @@ static void VerifyScriptBench(benchmark::State& state)
CScript scriptPubKey = CScript() << witnessversion << ToByteVector(pubkeyHash);
CScript scriptSig;
CScript witScriptPubkey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(pubkeyHash) << OP_EQUALVERIFY << OP_CHECKSIG;
- CTransaction txCredit = BuildCreditingTransaction(scriptPubKey);
+ const CMutableTransaction& txCredit = BuildCreditingTransaction(scriptPubKey);
CMutableTransaction txSpend = BuildSpendingTransaction(scriptSig, txCredit);
CScriptWitness& witness = txSpend.vin[0].scriptWitness;
witness.stack.emplace_back();
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 83d9719df2..0dc2dfbf7d 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -42,12 +42,9 @@
void WaitForShutdown()
{
- bool fShutdown = ShutdownRequested();
- // Tell the main threads to shutdown.
- while (!fShutdown)
+ while (!ShutdownRequested())
{
MilliSleep(200);
- fShutdown = ShutdownRequested();
}
Interrupt();
}
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/chainparamsbase.cpp b/src/chainparamsbase.cpp
index e840a2ed30..3ef9c2cfe5 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -47,4 +47,5 @@ std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain
void SelectBaseParams(const std::string& chain)
{
globalChainBaseParams = CreateBaseChainParams(chain);
+ gArgs.SelectConfigNetwork(chain);
}
diff --git a/src/compat.h b/src/compat.h
index 8a0f901304..920b3f776d 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -96,6 +96,12 @@ typedef int32_t ssize_t;
size_t strnlen( const char *start, size_t max_len);
#endif // HAVE_DECL_STRNLEN
+#ifndef WIN32
+typedef void* sockopt_arg_type;
+#else
+typedef char* sockopt_arg_type;
+#endif
+
bool static inline IsSelectableSocket(const SOCKET& s) {
#ifdef WIN32
return true;
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/core_write.cpp b/src/core_write.cpp
index 54b18a4931..929498ff28 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -161,6 +161,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
entry.pushKV("version", tx.nVersion);
entry.pushKV("size", (int)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION));
entry.pushKV("vsize", (GetTransactionWeight(tx) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR);
+ entry.pushKV("weight", GetTransactionWeight(tx));
entry.pushKV("locktime", (int64_t)tx.nLockTime);
UniValue vin(UniValue::VARR);
diff --git a/src/init.cpp b/src/init.cpp
index 486c84f5a3..8538630d7e 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -76,19 +76,18 @@ std::unique_ptr<PeerLogicValidation> peerLogic;
class DummyWalletInit : public WalletInitInterface {
public:
- std::string GetHelpString(bool showDebug) override {return std::string{};}
- bool ParameterInteraction() override {return true;}
- void RegisterRPC(CRPCTable &) override {}
- bool Verify() override {return true;}
- bool Open() override {LogPrintf("No wallet support compiled in!\n"); return true;}
- void Start(CScheduler& scheduler) override {}
- void Flush() override {}
- void Stop() override {}
- void Close() override {}
+ std::string GetHelpString(bool showDebug) const override {return std::string{};}
+ bool ParameterInteraction() const override {return true;}
+ void RegisterRPC(CRPCTable &) const override {}
+ bool Verify() const override {return true;}
+ bool Open() const override {LogPrintf("No wallet support compiled in!\n"); return true;}
+ void Start(CScheduler& scheduler) const override {}
+ void Flush() const override {}
+ void Stop() const override {}
+ void Close() const override {}
};
-static DummyWalletInit g_dummy_wallet_init;
-WalletInitInterface* const g_wallet_init_interface = &g_dummy_wallet_init;
+const WalletInitInterface& g_wallet_init_interface = DummyWalletInit();
#endif
#if ENABLE_ZMQ
@@ -204,7 +203,7 @@ void Shutdown()
StopREST();
StopRPC();
StopHTTPServer();
- g_wallet_init_interface->Flush();
+ g_wallet_init_interface.Flush();
StopMapPort();
// Because these depend on each-other, we make sure that neither can be
@@ -262,7 +261,7 @@ void Shutdown()
pcoinsdbview.reset();
pblocktree.reset();
}
- g_wallet_init_interface->Stop();
+ g_wallet_init_interface.Stop();
#if ENABLE_ZMQ
if (pzmqNotificationInterface) {
@@ -282,7 +281,7 @@ void Shutdown()
UnregisterAllValidationInterfaces();
GetMainSignals().UnregisterBackgroundSignalScheduler();
GetMainSignals().UnregisterWithMempoolSignals(mempool);
- g_wallet_init_interface->Close();
+ g_wallet_init_interface.Close();
globalVerifyHandle.reset();
ECC_Stop();
LogPrintf("%s: done\n", __func__);
@@ -425,7 +424,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-whitelist=<IP address or network>", _("Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple times.") +
" " + _("Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway"));
- strUsage += g_wallet_init_interface->GetHelpString(showDebug);
+ strUsage += g_wallet_init_interface.GetHelpString(showDebug);
#if ENABLE_ZMQ
strUsage += HelpMessageGroup(_("ZeroMQ notification options:"));
@@ -803,6 +802,11 @@ void InitParameterInteraction()
if (gArgs.SoftSetBoolArg("-whitelistrelay", true))
LogPrintf("%s: parameter interaction: -whitelistforcerelay=1 -> setting -whitelistrelay=1\n", __func__);
}
+
+ // Warn if network-specific options (-addnode, -connect, etc) are
+ // specified in default section of config file, but not overridden
+ // on the command line or in this network's section of the config file.
+ gArgs.WarnForSectionOnlyArgs();
}
static std::string ResolveErrMsg(const char * const optname, const std::string& strBind)
@@ -810,14 +814,25 @@ static std::string ResolveErrMsg(const char * const optname, const std::string&
return strprintf(_("Cannot resolve -%s address: '%s'"), optname, strBind);
}
+/**
+ * Initialize global loggers.
+ *
+ * Note that this is called very early in the process lifetime, so you should be
+ * careful about what global state you rely on here.
+ */
void InitLogging()
{
- fPrintToConsole = gArgs.GetBoolArg("-printtoconsole", false);
+ // Add newlines to the logfile to distinguish this execution from the last
+ // one; called before console logging is set up, so this is only sent to
+ // debug.log.
+ LogPrintf("\n\n\n\n\n");
+
+ fPrintToConsole = gArgs.GetBoolArg("-printtoconsole", !gArgs.GetBoolArg("-daemon", false));
+ fPrintToDebugLog = !gArgs.IsArgNegated("-debuglogfile");
fLogTimestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS);
fLogTimeMicros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS);
fLogIPs = gArgs.GetBoolArg("-logips", DEFAULT_LOGIPS);
- LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
std::string version_string = FormatFullVersion();
#ifdef DEBUG
version_string += " (debug build)";
@@ -1093,7 +1108,7 @@ bool AppInitParameterInteraction()
return InitError(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.NetworkIDString()));
nBytesPerSigOp = gArgs.GetArg("-bytespersigop", nBytesPerSigOp);
- if (!g_wallet_init_interface->ParameterInteraction()) return false;
+ if (!g_wallet_init_interface.ParameterInteraction()) return false;
fIsBareMultisigStd = gArgs.GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG);
fAcceptDatacarrier = gArgs.GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER);
@@ -1211,13 +1226,12 @@ bool AppInitMain()
#ifndef WIN32
CreatePidFile(GetPidFile(), getpid());
#endif
- if (gArgs.GetBoolArg("-shrinkdebugfile", logCategories == BCLog::NONE)) {
- // Do this first since it both loads a bunch of debug.log into memory,
- // and because this needs to happen before any other debug.log printing
- ShrinkDebugFile();
- }
-
if (fPrintToDebugLog) {
+ if (gArgs.GetBoolArg("-shrinkdebugfile", logCategories == BCLog::NONE)) {
+ // Do this first since it both loads a bunch of debug.log into memory,
+ // and because this needs to happen before any other debug.log printing
+ ShrinkDebugFile();
+ }
if (!OpenDebugLog()) {
return InitError(strprintf("Could not open debug log file %s", GetDebugLogPath().string()));
}
@@ -1259,7 +1273,7 @@ bool AppInitMain()
* available in the GUI RPC console even if external calls are disabled.
*/
RegisterAllCoreRPCCommands(tableRPC);
- g_wallet_init_interface->RegisterRPC(tableRPC);
+ g_wallet_init_interface.RegisterRPC(tableRPC);
/* Start the RPC server already. It will be started in "warmup" mode
* and not really process calls already (but it will signify connections
@@ -1276,7 +1290,7 @@ bool AppInitMain()
int64_t nStart;
// ********************************************************* Step 5: verify wallet database integrity
- if (!g_wallet_init_interface->Verify()) return false;
+ if (!g_wallet_init_interface.Verify()) return false;
// ********************************************************* Step 6: network initialization
// Note that we absolutely cannot open any actual connections
@@ -1595,7 +1609,7 @@ bool AppInitMain()
fFeeEstimatesInitialized = true;
// ********************************************************* Step 8: load wallet
- if (!g_wallet_init_interface->Open()) return false;
+ if (!g_wallet_init_interface.Open()) return false;
// ********************************************************* Step 9: data directory maintenance
@@ -1741,7 +1755,7 @@ bool AppInitMain()
SetRPCWarmupFinished();
uiInterface.InitMessage(_("Done loading"));
- g_wallet_init_interface->Start(scheduler);
+ g_wallet_init_interface.Start(scheduler);
return true;
}
diff --git a/src/init.h b/src/init.h
index 829c110112..000c8c95e4 100644
--- a/src/init.h
+++ b/src/init.h
@@ -13,7 +13,7 @@ class CScheduler;
class CWallet;
class WalletInitInterface;
-extern WalletInitInterface* const g_wallet_init_interface;
+extern const WalletInitInterface& g_wallet_init_interface;
namespace boost
{
diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp
index 919748f942..ddd5496a80 100644
--- a/src/interfaces/node.cpp
+++ b/src/interfaces/node.cpp
@@ -216,9 +216,6 @@ class NodeImpl : public Node
return result;
}
CFeeRate getDustRelayFee() override { return ::dustRelayFee; }
- CFeeRate getFallbackFee() override { CHECK_WALLET(return CWallet::fallbackFee); }
- CFeeRate getPayTxFee() override { CHECK_WALLET(return ::payTxFee); }
- void setPayTxFee(CFeeRate rate) override { CHECK_WALLET(::payTxFee = rate); }
UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) override
{
JSONRPCRequest req;
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index f375af2f19..84e869100a 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -173,15 +173,6 @@ public:
//! Get dust relay fee.
virtual CFeeRate getDustRelayFee() = 0;
- //! Get fallback fee.
- virtual CFeeRate getFallbackFee() = 0;
-
- //! Get pay tx fee.
- virtual CFeeRate getPayTxFee() = 0;
-
- //! Set pay tx fee.
- virtual void setPayTxFee(CFeeRate rate) = 0;
-
//! Execute rpc command.
virtual UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) = 0;
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.cpp b/src/net.cpp
index 356a66563f..cd076c1ce2 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1923,23 +1923,25 @@ std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo()
for (const std::string& strAddNode : lAddresses) {
CService service(LookupNumeric(strAddNode.c_str(), Params().GetDefaultPort()));
+ AddedNodeInfo addedNode{strAddNode, CService(), false, false};
if (service.IsValid()) {
// strAddNode is an IP:port
auto it = mapConnected.find(service);
if (it != mapConnected.end()) {
- ret.push_back(AddedNodeInfo{strAddNode, service, true, it->second});
- } else {
- ret.push_back(AddedNodeInfo{strAddNode, CService(), false, false});
+ addedNode.resolvedAddress = service;
+ addedNode.fConnected = true;
+ addedNode.fInbound = it->second;
}
} else {
// strAddNode is a name
auto it = mapConnectedByName.find(strAddNode);
if (it != mapConnectedByName.end()) {
- ret.push_back(AddedNodeInfo{strAddNode, it->second.second, true, it->second.first});
- } else {
- ret.push_back(AddedNodeInfo{strAddNode, CService(), false, false});
+ addedNode.resolvedAddress = it->second.second;
+ addedNode.fConnected = true;
+ addedNode.fInbound = it->second.first;
}
}
+ ret.emplace_back(std::move(addedNode));
}
return ret;
@@ -2088,23 +2090,16 @@ bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, b
LogPrintf("%s\n", strError);
return false;
}
-#ifndef WIN32
+
// Allow binding if the port is still in TIME_WAIT state after
// the program was closed and restarted.
- setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
-#else
- setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&nOne, sizeof(int));
-#endif
+ setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (sockopt_arg_type)&nOne, sizeof(int));
// some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
// and enable it by default or not. Try to enable it, if possible.
if (addrBind.IsIPv6()) {
#ifdef IPV6_V6ONLY
-#ifdef WIN32
- setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&nOne, sizeof(int));
-#else
- setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&nOne, sizeof(int));
-#endif
+ setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (sockopt_arg_type)&nOne, sizeof(int));
#endif
#ifdef WIN32
int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED;
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index 4f231d73c8..18d5948f85 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -14,7 +14,7 @@ static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43};
// 0xFD + sha256("bitcoin")[0:5]
static const unsigned char g_internal_prefix[] = { 0xFD, 0x6B, 0x88, 0xC0, 0x87, 0x24 };
-void CNetAddr::Init()
+CNetAddr::CNetAddr()
{
memset(ip, 0, sizeof(ip));
scopeId = 0;
@@ -67,11 +67,6 @@ bool CNetAddr::SetSpecial(const std::string &strName)
return false;
}
-CNetAddr::CNetAddr()
-{
- Init();
-}
-
CNetAddr::CNetAddr(const struct in_addr& ipv4Addr)
{
SetRaw(NET_IPV4, (const uint8_t*)&ipv4Addr);
@@ -290,11 +285,6 @@ bool operator==(const CNetAddr& a, const CNetAddr& b)
return (memcmp(a.ip, b.ip, 16) == 0);
}
-bool operator!=(const CNetAddr& a, const CNetAddr& b)
-{
- return (memcmp(a.ip, b.ip, 16) != 0);
-}
-
bool operator<(const CNetAddr& a, const CNetAddr& b)
{
return (memcmp(a.ip, b.ip, 16) < 0);
@@ -469,14 +459,8 @@ int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const
}
}
-void CService::Init()
+CService::CService() : port(0)
{
- port = 0;
-}
-
-CService::CService()
-{
- Init();
}
CService::CService(const CNetAddr& cip, unsigned short portIn) : CNetAddr(cip), port(portIn)
@@ -525,11 +509,6 @@ bool operator==(const CService& a, const CService& b)
return static_cast<CNetAddr>(a) == static_cast<CNetAddr>(b) && a.port == b.port;
}
-bool operator!=(const CService& a, const CService& b)
-{
- return static_cast<CNetAddr>(a) != static_cast<CNetAddr>(b) || a.port != b.port;
-}
-
bool operator<(const CService& a, const CService& b)
{
return static_cast<CNetAddr>(a) < static_cast<CNetAddr>(b) || (static_cast<CNetAddr>(a) == static_cast<CNetAddr>(b) && a.port < b.port);
@@ -663,16 +642,16 @@ bool CSubNet::Match(const CNetAddr &addr) const
static inline int NetmaskBits(uint8_t x)
{
switch(x) {
- case 0x00: return 0; break;
- case 0x80: return 1; break;
- case 0xc0: return 2; break;
- case 0xe0: return 3; break;
- case 0xf0: return 4; break;
- case 0xf8: return 5; break;
- case 0xfc: return 6; break;
- case 0xfe: return 7; break;
- case 0xff: return 8; break;
- default: return -1; break;
+ case 0x00: return 0;
+ case 0x80: return 1;
+ case 0xc0: return 2;
+ case 0xe0: return 3;
+ case 0xf0: return 4;
+ case 0xf8: return 5;
+ case 0xfc: return 6;
+ case 0xfe: return 7;
+ case 0xff: return 8;
+ default: return -1;
}
}
@@ -724,11 +703,6 @@ bool operator==(const CSubNet& a, const CSubNet& b)
return a.valid == b.valid && a.network == b.network && !memcmp(a.netmask, b.netmask, 16);
}
-bool operator!=(const CSubNet& a, const CSubNet& b)
-{
- return !(a==b);
-}
-
bool operator<(const CSubNet& a, const CSubNet& b)
{
return (a.network < b.network || (a.network == b.network && memcmp(a.netmask, b.netmask, 16) < 0));
diff --git a/src/netaddress.h b/src/netaddress.h
index 38f8709257..f8f2ab99ff 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -38,15 +38,16 @@ class CNetAddr
public:
CNetAddr();
explicit CNetAddr(const struct in_addr& ipv4Addr);
- void Init();
void SetIP(const CNetAddr& ip);
+ private:
/**
* Set raw IPv4 or IPv6 address (in network byte order)
* @note Only NET_IPV4 and NET_IPV6 are allowed for network.
*/
void SetRaw(Network network, const uint8_t *data);
+ public:
/**
* Transform an arbitrary string into a non-routable ipv6 address.
* Useful for mapping resolved addresses back to their source.
@@ -87,7 +88,7 @@ class CNetAddr
bool GetIn6Addr(struct in6_addr* pipv6Addr) const;
friend bool operator==(const CNetAddr& a, const CNetAddr& b);
- friend bool operator!=(const CNetAddr& a, const CNetAddr& b);
+ friend bool operator!=(const CNetAddr& a, const CNetAddr& b) { return !(a == b); }
friend bool operator<(const CNetAddr& a, const CNetAddr& b);
ADD_SERIALIZE_METHODS;
@@ -124,7 +125,7 @@ class CSubNet
bool IsValid() const;
friend bool operator==(const CSubNet& a, const CSubNet& b);
- friend bool operator!=(const CSubNet& a, const CSubNet& b);
+ friend bool operator!=(const CSubNet& a, const CSubNet& b) { return !(a == b); }
friend bool operator<(const CSubNet& a, const CSubNet& b);
ADD_SERIALIZE_METHODS;
@@ -148,12 +149,11 @@ class CService : public CNetAddr
CService(const CNetAddr& ip, unsigned short port);
CService(const struct in_addr& ipv4Addr, unsigned short port);
explicit CService(const struct sockaddr_in& addr);
- void Init();
unsigned short GetPort() const;
bool GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const;
bool SetSockAddr(const struct sockaddr* paddr);
friend bool operator==(const CService& a, const CService& b);
- friend bool operator!=(const CService& a, const CService& b);
+ friend bool operator!=(const CService& a, const CService& b) { return !(a == b); }
friend bool operator<(const CService& a, const CService& b);
std::vector<unsigned char> GetKey() const;
std::string ToString() const;
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 5d3d2f25c8..57835b5427 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -513,11 +513,7 @@ bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, i
return false;
}
socklen_t nRetSize = sizeof(nRet);
-#ifdef WIN32
- if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR)
-#else
- if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR)
-#endif
+ if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (sockopt_arg_type)&nRet, &nRetSize) == SOCKET_ERROR)
{
LogPrintf("getsockopt() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
return false;
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 543e4fc358..7bdf09812b 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -94,6 +94,7 @@ UniValue getrawtransaction(const JSONRPCRequest& request)
" \"hash\" : \"id\", (string) The transaction hash (differs from txid for witness transactions)\n"
" \"size\" : n, (numeric) The serialized transaction size\n"
" \"vsize\" : n, (numeric) The virtual transaction size (differs from size for witness transactions)\n"
+ " \"weight\" : n, (numeric) The transaction's weight (between vsize*4-3 and vsize*4)\n"
" \"version\" : n, (numeric) The version\n"
" \"locktime\" : ttt, (numeric) The lock time\n"
" \"vin\" : [ (array of json objects)\n"
@@ -494,6 +495,7 @@ UniValue decoderawtransaction(const JSONRPCRequest& request)
" \"hash\" : \"id\", (string) The transaction hash (differs from txid for witness transactions)\n"
" \"size\" : n, (numeric) The transaction size\n"
" \"vsize\" : n, (numeric) The virtual transaction size (differs from size for witness transactions)\n"
+ " \"weight\" : n, (numeric) The transaction's weight (between vsize*4 - 3 and vsize*4)\n"
" \"version\" : n, (numeric) The version\n"
" \"locktime\" : ttt, (numeric) The lock time\n"
" \"vin\" : [ (array of json objects)\n"
diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp
index 32330e0548..8cffacbffe 100644
--- a/src/test/blockencodings_tests.cpp
+++ b/src/test/blockencodings_tests.cpp
@@ -52,8 +52,8 @@ static CBlock BuildBlockTestCase() {
}
// Number of shared use_counts we expect for a tx we haven't touched
-// == 2 (mempool + our copy from the GetSharedTx call)
-#define SHARED_TX_OFFSET 2
+// (block + mempool + our copy from the GetSharedTx call)
+constexpr long SHARED_TX_OFFSET{3};
BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)
{
@@ -61,7 +61,7 @@ BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)
TestMemPoolEntryHelper entry;
CBlock block(BuildBlockTestCase());
- pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(*block.vtx[2]));
+ pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(block.vtx[2]));
LOCK(pool.cs);
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
@@ -161,7 +161,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
TestMemPoolEntryHelper entry;
CBlock block(BuildBlockTestCase());
- pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(*block.vtx[2]));
+ pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(block.vtx[2]));
LOCK(pool.cs);
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
@@ -188,7 +188,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
BOOST_CHECK( partialBlock.IsTxAvailable(1));
BOOST_CHECK( partialBlock.IsTxAvailable(2));
- BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1);
+ BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); // +1 because of partialBlock
CBlock block2;
{
@@ -203,6 +203,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
partialBlock.FillBlock(block2, {block.vtx[1]}); // Current implementation doesn't check txn here, but don't require that
partialBlock = tmp;
}
+ BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 2); // +2 because of partialBlock and block2
bool mutated;
BOOST_CHECK(block.hashMerkleRoot != BlockMerkleRoot(block2, &mutated));
@@ -213,13 +214,15 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block3, &mutated).ToString());
BOOST_CHECK(!mutated);
+ BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 3); // +2 because of partialBlock and block2 and block3
+
txhash = block.vtx[2]->GetHash();
block.vtx.clear();
block2.vtx.clear();
block3.vtx.clear();
- BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); // + 1 because of partialBlockCopy.
+ BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1 - 1); // + 1 because of partialBlock; -1 because of block.
}
- BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
+ BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET - 1); // -1 because of block
}
BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
@@ -228,7 +231,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
TestMemPoolEntryHelper entry;
CBlock block(BuildBlockTestCase());
- pool.addUnchecked(block.vtx[1]->GetHash(), entry.FromTx(*block.vtx[1]));
+ pool.addUnchecked(block.vtx[1]->GetHash(), entry.FromTx(block.vtx[1]));
LOCK(pool.cs);
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
@@ -268,9 +271,9 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
txhash = block.vtx[1]->GetHash();
block.vtx.clear();
block2.vtx.clear();
- BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); // + 1 because of partialBlockCopy.
+ BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1 - 1); // + 1 because of partialBlock; -1 because of block.
}
- BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
+ BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET - 1); // -1 because of block
}
BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index b593f9633c..066f6328a6 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -19,7 +19,7 @@
BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup)
CScript
-sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transaction, int whichIn)
+sign_multisig(const CScript& scriptPubKey, const std::vector<CKey>& keys, const CTransaction& transaction, int whichIn)
{
uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, SigVersion::BASE);
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 46a2d13745..a06b573b37 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -1029,7 +1029,7 @@ BOOST_AUTO_TEST_CASE(script_PushData)
}
CScript
-sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transaction)
+sign_multisig(const CScript& scriptPubKey, const std::vector<CKey>& keys, const CTransaction& transaction)
{
uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL, 0, SigVersion::BASE);
@@ -1053,7 +1053,7 @@ sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transac
return result;
}
CScript
-sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction)
+sign_multisig(const CScript& scriptPubKey, const CKey& key, const CTransaction& transaction)
{
std::vector<CKey> keys;
keys.push_back(key);
diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp
index 94164346f3..eba58e0042 100644
--- a/src/test/serialize_tests.cpp
+++ b/src/test/serialize_tests.cpp
@@ -23,7 +23,7 @@ protected:
CTransactionRef txval;
public:
CSerializeMethodsTestSingle() = default;
- CSerializeMethodsTestSingle(int intvalin, bool boolvalin, std::string stringvalin, const char* charstrvalin, CTransaction txvalin) : intval(intvalin), boolval(boolvalin), stringval(std::move(stringvalin)), txval(MakeTransactionRef(txvalin))
+ CSerializeMethodsTestSingle(int intvalin, bool boolvalin, std::string stringvalin, const char* charstrvalin, const CTransactionRef& txvalin) : intval(intvalin), boolval(boolvalin), stringval(std::move(stringvalin)), txval(txvalin)
{
memcpy(charstrval, charstrvalin, sizeof(charstrval));
}
@@ -350,8 +350,9 @@ BOOST_AUTO_TEST_CASE(class_methods)
std::string stringval("testing");
const char charstrval[16] = "testing charstr";
CMutableTransaction txval;
- CSerializeMethodsTestSingle methodtest1(intval, boolval, stringval, charstrval, txval);
- CSerializeMethodsTestMany methodtest2(intval, boolval, stringval, charstrval, txval);
+ CTransactionRef tx_ref{MakeTransactionRef(txval)};
+ CSerializeMethodsTestSingle methodtest1(intval, boolval, stringval, charstrval, tx_ref);
+ CSerializeMethodsTestMany methodtest2(intval, boolval, stringval, charstrval, tx_ref);
CSerializeMethodsTestSingle methodtest3;
CSerializeMethodsTestMany methodtest4;
CDataStream ss(SER_DISK, PROTOCOL_VERSION);
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index ff20d4b3d7..b72df1604f 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -123,7 +123,7 @@ TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST)
{
std::vector<CMutableTransaction> noTxns;
CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey);
- coinbaseTxns.push_back(*b.vtx[0]);
+ m_coinbase_txns.push_back(b.vtx[0]);
}
}
@@ -164,12 +164,12 @@ TestChain100Setup::~TestChain100Setup()
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx) {
- CTransaction txn(tx);
- return FromTx(txn);
+ return FromTx(MakeTransactionRef(tx));
}
-CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransaction &txn) {
- return CTxMemPoolEntry(MakeTransactionRef(txn), nFee, nTime, nHeight,
+CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransactionRef& tx)
+{
+ return CTxMemPoolEntry(tx, nFee, nTime, nHeight,
spendsCoinbase, sigOpCost, lp);
}
diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h
index 8136da3aa9..1f91eb622c 100644
--- a/src/test/test_bitcoin.h
+++ b/src/test/test_bitcoin.h
@@ -87,7 +87,7 @@ struct TestChain100Setup : public TestingSetup {
~TestChain100Setup();
- std::vector<CTransaction> coinbaseTxns; // For convenience, coinbase transactions
+ std::vector<CTransactionRef> m_coinbase_txns; // For convenience, coinbase transactions
CKey coinbaseKey; // private/public key needed to spend coinbase transactions
};
@@ -107,8 +107,8 @@ struct TestMemPoolEntryHelper
nFee(0), nTime(0), nHeight(1),
spendsCoinbase(false), sigOpCost(4) { }
- CTxMemPoolEntry FromTx(const CMutableTransaction &tx);
- CTxMemPoolEntry FromTx(const CTransaction &tx);
+ CTxMemPoolEntry FromTx(const CMutableTransaction& tx);
+ CTxMemPoolEntry FromTx(const CTransactionRef& tx);
// Change the default value
TestMemPoolEntryHelper &Fee(CAmount _fee) { nFee = _fee; return *this; }
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index 71f3d727b1..7a52697859 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -48,7 +48,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
{
spends[i].nVersion = 1;
spends[i].vin.resize(1);
- spends[i].vin[0].prevout.hash = coinbaseTxns[0].GetHash();
+ spends[i].vin[0].prevout.hash = m_coinbase_txns[0]->GetHash();
spends[i].vin[0].prevout.n = 0;
spends[i].vout.resize(1);
spends[i].vout[0].nValue = 11*CENT;
@@ -167,7 +167,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
spend_tx.nVersion = 1;
spend_tx.vin.resize(1);
- spend_tx.vin[0].prevout.hash = coinbaseTxns[0].GetHash();
+ spend_tx.vin[0].prevout.hash = m_coinbase_txns[0]->GetHash();
spend_tx.vin[0].prevout.n = 0;
spend_tx.vout.resize(4);
spend_tx.vout[0].nValue = 11*CENT;
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index e8c7b80c3a..344113b60c 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -176,13 +176,22 @@ BOOST_AUTO_TEST_CASE(util_FormatISO8601Time)
struct TestArgsManager : public ArgsManager
{
- std::map<std::string, std::string>& GetMapArgs() { return mapArgs; }
- const std::map<std::string, std::vector<std::string> >& GetMapMultiArgs() { return mapMultiArgs; }
- const std::unordered_set<std::string>& GetNegatedArgs() { return m_negated_args; }
+ TestArgsManager() { m_network_only_args.clear(); }
+ std::map<std::string, std::vector<std::string> >& GetOverrideArgs() { return m_override_args; }
+ std::map<std::string, std::vector<std::string> >& GetConfigArgs() { return m_config_args; }
void ReadConfigString(const std::string str_config)
{
- std::istringstream stream(str_config);
- ReadConfigStream(stream);
+ std::istringstream streamConfig(str_config);
+ {
+ LOCK(cs_args);
+ m_config_args.clear();
+ }
+ ReadConfigStream(streamConfig);
+ }
+ void SetNetworkOnlyArg(const std::string arg)
+ {
+ LOCK(cs_args);
+ m_network_only_args.insert(arg);
}
};
@@ -192,22 +201,26 @@ BOOST_AUTO_TEST_CASE(util_ParseParameters)
const char *argv_test[] = {"-ignored", "-a", "-b", "-ccc=argument", "-ccc=multiple", "f", "-d=e"};
testArgs.ParseParameters(0, (char**)argv_test);
- BOOST_CHECK(testArgs.GetMapArgs().empty() && testArgs.GetMapMultiArgs().empty());
+ BOOST_CHECK(testArgs.GetOverrideArgs().empty() && testArgs.GetConfigArgs().empty());
testArgs.ParseParameters(1, (char**)argv_test);
- BOOST_CHECK(testArgs.GetMapArgs().empty() && testArgs.GetMapMultiArgs().empty());
+ BOOST_CHECK(testArgs.GetOverrideArgs().empty() && testArgs.GetConfigArgs().empty());
testArgs.ParseParameters(7, (char**)argv_test);
// expectation: -ignored is ignored (program name argument),
// -a, -b and -ccc end up in map, -d ignored because it is after
// a non-option argument (non-GNU option parsing)
- BOOST_CHECK(testArgs.GetMapArgs().size() == 3 && testArgs.GetMapMultiArgs().size() == 3);
+ BOOST_CHECK(testArgs.GetOverrideArgs().size() == 3 && testArgs.GetConfigArgs().empty());
BOOST_CHECK(testArgs.IsArgSet("-a") && testArgs.IsArgSet("-b") && testArgs.IsArgSet("-ccc")
&& !testArgs.IsArgSet("f") && !testArgs.IsArgSet("-d"));
- BOOST_CHECK(testArgs.GetMapMultiArgs().count("-a") && testArgs.GetMapMultiArgs().count("-b") && testArgs.GetMapMultiArgs().count("-ccc")
- && !testArgs.GetMapMultiArgs().count("f") && !testArgs.GetMapMultiArgs().count("-d"));
-
- BOOST_CHECK(testArgs.GetMapArgs()["-a"] == "" && testArgs.GetMapArgs()["-ccc"] == "multiple");
+ BOOST_CHECK(testArgs.GetOverrideArgs().count("-a") && testArgs.GetOverrideArgs().count("-b") && testArgs.GetOverrideArgs().count("-ccc")
+ && !testArgs.GetOverrideArgs().count("f") && !testArgs.GetOverrideArgs().count("-d"));
+
+ BOOST_CHECK(testArgs.GetOverrideArgs()["-a"].size() == 1);
+ BOOST_CHECK(testArgs.GetOverrideArgs()["-a"].front() == "");
+ BOOST_CHECK(testArgs.GetOverrideArgs()["-ccc"].size() == 2);
+ BOOST_CHECK(testArgs.GetOverrideArgs()["-ccc"].front() == "argument");
+ BOOST_CHECK(testArgs.GetOverrideArgs()["-ccc"].back() == "multiple");
BOOST_CHECK(testArgs.GetArgs("-ccc").size() == 2);
}
@@ -223,15 +236,14 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArg)
BOOST_CHECK(testArgs.IsArgSet({'-', opt}) || !opt);
// Nothing else should be in the map
- BOOST_CHECK(testArgs.GetMapArgs().size() == 6 &&
- testArgs.GetMapMultiArgs().size() == 6);
+ BOOST_CHECK(testArgs.GetOverrideArgs().size() == 6 &&
+ testArgs.GetConfigArgs().empty());
// The -no prefix should get stripped on the way in.
BOOST_CHECK(!testArgs.IsArgSet("-nob"));
// The -b option is flagged as negated, and nothing else is
BOOST_CHECK(testArgs.IsArgNegated("-b"));
- BOOST_CHECK(testArgs.GetNegatedArgs().size() == 1);
BOOST_CHECK(!testArgs.IsArgNegated("-a"));
// Check expected values.
@@ -256,8 +268,8 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases)
BOOST_CHECK(!testArgs.IsArgNegated("-foo"));
BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "");
- // A double negative is a positive.
- BOOST_CHECK(testArgs.IsArgNegated("-bar"));
+ // A double negative is a positive, and not marked as negated.
+ BOOST_CHECK(!testArgs.IsArgNegated("-bar"));
BOOST_CHECK(testArgs.GetArg("-bar", "xxx") == "1");
// Config test
@@ -266,12 +278,12 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases)
testArgs.ReadConfigString(conf_test);
// This was passed twice, second one overrides the negative setting,
- // but not the value.
+ // and the value.
BOOST_CHECK(!testArgs.IsArgNegated("-foo"));
- BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "0");
+ BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "1");
- // A double negative is a positive.
- BOOST_CHECK(testArgs.IsArgNegated("-bar"));
+ // A double negative is a positive, and does not count as negated.
+ BOOST_CHECK(!testArgs.IsArgNegated("-bar"));
BOOST_CHECK(testArgs.GetArg("-bar", "xxx") == "1");
// Combined test
@@ -281,18 +293,15 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases)
testArgs.ReadConfigString(combo_test_conf);
// Command line overrides, but doesn't erase old setting
- BOOST_CHECK(!testArgs.IsArgNegated("-foo"));
+ BOOST_CHECK(testArgs.IsArgNegated("-foo"));
BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "0");
- BOOST_CHECK(testArgs.GetArgs("-foo").size() == 2
- && testArgs.GetArgs("-foo").front() == "0"
- && testArgs.GetArgs("-foo").back() == "1");
+ BOOST_CHECK(testArgs.GetArgs("-foo").size() == 0);
// Command line overrides, but doesn't erase old setting
- BOOST_CHECK(testArgs.IsArgNegated("-bar"));
+ BOOST_CHECK(!testArgs.IsArgNegated("-bar"));
BOOST_CHECK(testArgs.GetArg("-bar", "xxx") == "");
- BOOST_CHECK(testArgs.GetArgs("-bar").size() == 2
- && testArgs.GetArgs("-bar").front() == ""
- && testArgs.GetArgs("-bar").back() == "0");
+ BOOST_CHECK(testArgs.GetArgs("-bar").size() == 1
+ && testArgs.GetArgs("-bar").front() == "");
}
BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
@@ -308,24 +317,39 @@ BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
"h=1\n"
"noh=1\n"
"noi=1\n"
- "i=1\n";
+ "i=1\n"
+ "sec1.ccc=extend1\n"
+ "\n"
+ "[sec1]\n"
+ "ccc=extend2\n"
+ "d=eee\n"
+ "h=1\n"
+ "[sec2]\n"
+ "ccc=extend3\n"
+ "iii=2\n";
TestArgsManager test_args;
test_args.ReadConfigString(str_config);
// expectation: a, b, ccc, d, fff, ggg, h, i end up in map
-
- BOOST_CHECK(test_args.GetMapArgs().size() == 8);
- BOOST_CHECK(test_args.GetMapMultiArgs().size() == 8);
-
- BOOST_CHECK(test_args.GetMapArgs().count("-a")
- && test_args.GetMapArgs().count("-b")
- && test_args.GetMapArgs().count("-ccc")
- && test_args.GetMapArgs().count("-d")
- && test_args.GetMapArgs().count("-fff")
- && test_args.GetMapArgs().count("-ggg")
- && test_args.GetMapArgs().count("-h")
- && test_args.GetMapArgs().count("-i")
+ // so do sec1.ccc, sec1.d, sec1.h, sec2.ccc, sec2.iii
+
+ BOOST_CHECK(test_args.GetOverrideArgs().empty());
+ BOOST_CHECK(test_args.GetConfigArgs().size() == 13);
+
+ BOOST_CHECK(test_args.GetConfigArgs().count("-a")
+ && test_args.GetConfigArgs().count("-b")
+ && test_args.GetConfigArgs().count("-ccc")
+ && test_args.GetConfigArgs().count("-d")
+ && test_args.GetConfigArgs().count("-fff")
+ && test_args.GetConfigArgs().count("-ggg")
+ && test_args.GetConfigArgs().count("-h")
+ && test_args.GetConfigArgs().count("-i")
+ );
+ BOOST_CHECK(test_args.GetConfigArgs().count("-sec1.ccc")
+ && test_args.GetConfigArgs().count("-sec1.h")
+ && test_args.GetConfigArgs().count("-sec2.ccc")
+ && test_args.GetConfigArgs().count("-sec2.iii")
);
BOOST_CHECK(test_args.IsArgSet("-a")
@@ -337,6 +361,7 @@ BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
&& test_args.IsArgSet("-h")
&& test_args.IsArgSet("-i")
&& !test_args.IsArgSet("-zzz")
+ && !test_args.IsArgSet("-iii")
);
BOOST_CHECK(test_args.GetArg("-a", "xxx") == ""
@@ -345,9 +370,10 @@ BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
&& test_args.GetArg("-d", "xxx") == "e"
&& test_args.GetArg("-fff", "xxx") == "0"
&& test_args.GetArg("-ggg", "xxx") == "1"
- && test_args.GetArg("-h", "xxx") == "1" // 1st value takes precedence
- && test_args.GetArg("-i", "xxx") == "0" // 1st value takes precedence
+ && test_args.GetArg("-h", "xxx") == "0"
+ && test_args.GetArg("-i", "xxx") == "1"
&& test_args.GetArg("-zzz", "xxx") == "xxx"
+ && test_args.GetArg("-iii", "xxx") == "xxx"
);
for (bool def : {false, true}) {
@@ -357,9 +383,10 @@ BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
&& !test_args.GetBoolArg("-d", def)
&& !test_args.GetBoolArg("-fff", def)
&& test_args.GetBoolArg("-ggg", def)
- && test_args.GetBoolArg("-h", def)
- && !test_args.GetBoolArg("-i", def)
+ && !test_args.GetBoolArg("-h", def)
+ && test_args.GetBoolArg("-i", def)
&& test_args.GetBoolArg("-zzz", def) == def
+ && test_args.GetBoolArg("-iii", def) == def
);
}
@@ -370,19 +397,15 @@ BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2
&& test_args.GetArgs("-ccc").front() == "argument"
&& test_args.GetArgs("-ccc").back() == "multiple");
- BOOST_CHECK(test_args.GetArgs("-fff").size() == 1
- && test_args.GetArgs("-fff").front() == "0");
+ BOOST_CHECK(test_args.GetArgs("-fff").size() == 0);
BOOST_CHECK(test_args.GetArgs("-nofff").size() == 0);
BOOST_CHECK(test_args.GetArgs("-ggg").size() == 1
&& test_args.GetArgs("-ggg").front() == "1");
BOOST_CHECK(test_args.GetArgs("-noggg").size() == 0);
- BOOST_CHECK(test_args.GetArgs("-h").size() == 2
- && test_args.GetArgs("-h").front() == "1"
- && test_args.GetArgs("-h").back() == "0");
+ BOOST_CHECK(test_args.GetArgs("-h").size() == 0);
BOOST_CHECK(test_args.GetArgs("-noh").size() == 0);
- BOOST_CHECK(test_args.GetArgs("-i").size() == 2
- && test_args.GetArgs("-i").front() == "0"
- && test_args.GetArgs("-i").back() == "1");
+ BOOST_CHECK(test_args.GetArgs("-i").size() == 1
+ && test_args.GetArgs("-i").front() == "1");
BOOST_CHECK(test_args.GetArgs("-noi").size() == 0);
BOOST_CHECK(test_args.GetArgs("-zzz").size() == 0);
@@ -391,25 +414,98 @@ BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
BOOST_CHECK(!test_args.IsArgNegated("-ccc"));
BOOST_CHECK(!test_args.IsArgNegated("-d"));
BOOST_CHECK(test_args.IsArgNegated("-fff"));
- BOOST_CHECK(test_args.IsArgNegated("-ggg")); // IsArgNegated==true when noggg=0
+ BOOST_CHECK(!test_args.IsArgNegated("-ggg"));
BOOST_CHECK(test_args.IsArgNegated("-h")); // last setting takes precedence
BOOST_CHECK(!test_args.IsArgNegated("-i")); // last setting takes precedence
BOOST_CHECK(!test_args.IsArgNegated("-zzz"));
+
+ // Test sections work
+ test_args.SelectConfigNetwork("sec1");
+
+ // same as original
+ BOOST_CHECK(test_args.GetArg("-a", "xxx") == ""
+ && test_args.GetArg("-b", "xxx") == "1"
+ && test_args.GetArg("-fff", "xxx") == "0"
+ && test_args.GetArg("-ggg", "xxx") == "1"
+ && test_args.GetArg("-zzz", "xxx") == "xxx"
+ && test_args.GetArg("-iii", "xxx") == "xxx"
+ );
+ // d is overridden
+ BOOST_CHECK(test_args.GetArg("-d", "xxx") == "eee");
+ // section-specific setting
+ BOOST_CHECK(test_args.GetArg("-h", "xxx") == "1");
+ // section takes priority for multiple values
+ BOOST_CHECK(test_args.GetArg("-ccc", "xxx") == "extend1");
+ // check multiple values works
+ const std::vector<std::string> sec1_ccc_expected = {"extend1","extend2","argument","multiple"};
+ const auto& sec1_ccc_res = test_args.GetArgs("-ccc");
+ BOOST_CHECK_EQUAL_COLLECTIONS(sec1_ccc_res.begin(), sec1_ccc_res.end(), sec1_ccc_expected.begin(), sec1_ccc_expected.end());
+
+ test_args.SelectConfigNetwork("sec2");
+
+ // same as original
+ BOOST_CHECK(test_args.GetArg("-a", "xxx") == ""
+ && test_args.GetArg("-b", "xxx") == "1"
+ && test_args.GetArg("-d", "xxx") == "e"
+ && test_args.GetArg("-fff", "xxx") == "0"
+ && test_args.GetArg("-ggg", "xxx") == "1"
+ && test_args.GetArg("-zzz", "xxx") == "xxx"
+ && test_args.GetArg("-h", "xxx") == "0"
+ );
+ // section-specific setting
+ BOOST_CHECK(test_args.GetArg("-iii", "xxx") == "2");
+ // section takes priority for multiple values
+ BOOST_CHECK(test_args.GetArg("-ccc", "xxx") == "extend3");
+ // check multiple values works
+ const std::vector<std::string> sec2_ccc_expected = {"extend3","argument","multiple"};
+ const auto& sec2_ccc_res = test_args.GetArgs("-ccc");
+ BOOST_CHECK_EQUAL_COLLECTIONS(sec2_ccc_res.begin(), sec2_ccc_res.end(), sec2_ccc_expected.begin(), sec2_ccc_expected.end());
+
+ // Test section only options
+
+ test_args.SetNetworkOnlyArg("-d");
+ test_args.SetNetworkOnlyArg("-ccc");
+ test_args.SetNetworkOnlyArg("-h");
+
+ test_args.SelectConfigNetwork(CBaseChainParams::MAIN);
+ BOOST_CHECK(test_args.GetArg("-d", "xxx") == "e");
+ BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2);
+ BOOST_CHECK(test_args.GetArg("-h", "xxx") == "0");
+
+ test_args.SelectConfigNetwork("sec1");
+ BOOST_CHECK(test_args.GetArg("-d", "xxx") == "eee");
+ BOOST_CHECK(test_args.GetArgs("-d").size() == 1);
+ BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2);
+ BOOST_CHECK(test_args.GetArg("-h", "xxx") == "1");
+
+ test_args.SelectConfigNetwork("sec2");
+ BOOST_CHECK(test_args.GetArg("-d", "xxx") == "xxx");
+ BOOST_CHECK(test_args.GetArgs("-d").size() == 0);
+ BOOST_CHECK(test_args.GetArgs("-ccc").size() == 1);
+ BOOST_CHECK(test_args.GetArg("-h", "xxx") == "0");
}
BOOST_AUTO_TEST_CASE(util_GetArg)
{
TestArgsManager testArgs;
- testArgs.GetMapArgs().clear();
- testArgs.GetMapArgs()["strtest1"] = "string...";
+ testArgs.GetOverrideArgs().clear();
+ testArgs.GetOverrideArgs()["strtest1"] = {"string..."};
// strtest2 undefined on purpose
- testArgs.GetMapArgs()["inttest1"] = "12345";
- testArgs.GetMapArgs()["inttest2"] = "81985529216486895";
+ testArgs.GetOverrideArgs()["inttest1"] = {"12345"};
+ testArgs.GetOverrideArgs()["inttest2"] = {"81985529216486895"};
// inttest3 undefined on purpose
- testArgs.GetMapArgs()["booltest1"] = "";
+ testArgs.GetOverrideArgs()["booltest1"] = {""};
// booltest2 undefined on purpose
- testArgs.GetMapArgs()["booltest3"] = "0";
- testArgs.GetMapArgs()["booltest4"] = "1";
+ testArgs.GetOverrideArgs()["booltest3"] = {"0"};
+ testArgs.GetOverrideArgs()["booltest4"] = {"1"};
+
+ // priorities
+ testArgs.GetOverrideArgs()["pritest1"] = {"a", "b"};
+ testArgs.GetConfigArgs()["pritest2"] = {"a", "b"};
+ testArgs.GetOverrideArgs()["pritest3"] = {"a"};
+ testArgs.GetConfigArgs()["pritest3"] = {"b"};
+ testArgs.GetOverrideArgs()["pritest4"] = {"a","b"};
+ testArgs.GetConfigArgs()["pritest4"] = {"c","d"};
BOOST_CHECK_EQUAL(testArgs.GetArg("strtest1", "default"), "string...");
BOOST_CHECK_EQUAL(testArgs.GetArg("strtest2", "default"), "default");
@@ -420,6 +516,11 @@ BOOST_AUTO_TEST_CASE(util_GetArg)
BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest2", false), false);
BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest3", false), false);
BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest4", false), true);
+
+ BOOST_CHECK_EQUAL(testArgs.GetArg("pritest1", "default"), "b");
+ BOOST_CHECK_EQUAL(testArgs.GetArg("pritest2", "default"), "a");
+ BOOST_CHECK_EQUAL(testArgs.GetArg("pritest3", "default"), "a");
+ BOOST_CHECK_EQUAL(testArgs.GetArg("pritest4", "default"), "b");
}
BOOST_AUTO_TEST_CASE(util_GetChainName)
@@ -432,7 +533,8 @@ BOOST_AUTO_TEST_CASE(util_GetChainName)
const char* argv_both[] = {"cmd", "-testnet", "-regtest"};
// equivalent to "-testnet"
- const char* testnetconf = "testnet=1\nregtest=0\n";
+ // regtest in testnet section is ignored
+ const char* testnetconf = "testnet=1\nregtest=0\n[test]\nregtest=1";
test_args.ParseParameters(0, (char**)argv_testnet);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "main");
@@ -468,6 +570,30 @@ BOOST_AUTO_TEST_CASE(util_GetChainName)
test_args.ParseParameters(3, (char**)argv_both);
test_args.ReadConfigString(testnetconf);
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_args.SelectConfigNetwork("test");
+
+ test_args.ParseParameters(0, (char**)argv_testnet);
+ test_args.ReadConfigString(testnetconf);
+ BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
+
+ test_args.ParseParameters(2, (char**)argv_testnet);
+ test_args.ReadConfigString(testnetconf);
+ BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
+
+ test_args.ParseParameters(2, (char**)argv_regtest);
+ test_args.ReadConfigString(testnetconf);
+ BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
+
+ test_args.ParseParameters(2, (char**)argv_test_no_reg);
+ test_args.ReadConfigString(testnetconf);
+ BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
+
+ test_args.ParseParameters(3, (char**)argv_both);
+ test_args.ReadConfigString(testnetconf);
+ BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
}
BOOST_AUTO_TEST_CASE(util_FormatMoney)
diff --git a/src/util.cpp b/src/util.cpp
index f55c9c8c34..4fb027b731 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,233 +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);
- }
- else 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
@@ -455,39 +218,204 @@ static bool InterpretBool(const std::string& strValue)
return (atoi(strValue) != 0);
}
+/** Internal helper functions for ArgsManager */
+class ArgsManagerHelper {
+public:
+ typedef std::map<std::string, std::vector<std::string>> MapArgs;
+
+ /** Determine whether to use config settings in the default section,
+ * See also comments around ArgsManager::ArgsManager() below. */
+ static inline bool UseDefaultSection(const ArgsManager& am, const std::string& arg)
+ {
+ return (am.m_network == CBaseChainParams::MAIN || am.m_network_only_args.count(arg) == 0);
+ }
+
+ /** Convert regular argument into the network-specific setting */
+ static inline std::string NetworkArg(const ArgsManager& am, const std::string& arg)
+ {
+ assert(arg.length() > 1 && arg[0] == '-');
+ return "-" + am.m_network + "." + arg.substr(1);
+ }
+
+ /** Find arguments in a map and add them to a vector */
+ static inline void AddArgs(std::vector<std::string>& res, const MapArgs& map_args, const std::string& arg)
+ {
+ auto it = map_args.find(arg);
+ if (it != map_args.end()) {
+ res.insert(res.end(), it->second.begin(), it->second.end());
+ }
+ }
+
+ /** Return true/false if an argument is set in a map, and also
+ * return the first (or last) of the possibly multiple values it has
+ */
+ static inline std::pair<bool,std::string> GetArgHelper(const MapArgs& map_args, const std::string& arg, bool getLast = false)
+ {
+ auto it = map_args.find(arg);
+
+ if (it == map_args.end() || it->second.empty()) {
+ return std::make_pair(false, std::string());
+ }
+
+ if (getLast) {
+ return std::make_pair(true, it->second.back());
+ } else {
+ return std::make_pair(true, it->second.front());
+ }
+ }
+
+ /* Get the string value of an argument, returning a pair of a boolean
+ * indicating the argument was found, and the value for the argument
+ * if it was found (or the empty string if not found).
+ */
+ static inline std::pair<bool,std::string> GetArg(const ArgsManager &am, const std::string& arg)
+ {
+ LOCK(am.cs_args);
+ std::pair<bool,std::string> found_result(false, std::string());
+
+ // We pass "true" to GetArgHelper in order to return the last
+ // argument value seen from the command line (so "bitcoind -foo=bar
+ // -foo=baz" gives GetArg(am,"foo")=={true,"baz"}
+ found_result = GetArgHelper(am.m_override_args, arg, true);
+ if (found_result.first) {
+ return found_result;
+ }
+
+ // But in contrast we return the first argument seen in a config file,
+ // so "foo=bar \n foo=baz" in the config file gives
+ // GetArg(am,"foo")={true,"bar"}
+ if (!am.m_network.empty()) {
+ found_result = GetArgHelper(am.m_config_args, NetworkArg(am, arg));
+ if (found_result.first) {
+ return found_result;
+ }
+ }
+
+ if (UseDefaultSection(am, arg)) {
+ found_result = GetArgHelper(am.m_config_args, arg);
+ if (found_result.first) {
+ return found_result;
+ }
+ }
+
+ return found_result;
+ }
+
+ /* Special test for -testnet and -regtest args, because we
+ * don't want to be confused by craziness like "[regtest] testnet=1"
+ */
+ static inline bool GetNetBoolArg(const ArgsManager &am, const std::string& net_arg)
+ {
+ std::pair<bool,std::string> found_result(false,std::string());
+ found_result = GetArgHelper(am.m_override_args, net_arg, true);
+ if (!found_result.first) {
+ found_result = GetArgHelper(am.m_config_args, net_arg, true);
+ if (!found_result.first) {
+ return false; // not set
+ }
+ }
+ return InterpretBool(found_result.second); // is set, so evaluate
+ }
+};
+
/**
* Interpret -nofoo as if the user supplied -foo=0.
*
- * This method also tracks when the -no form was supplied, and treats "-foo" as
- * a negated option when this happens. This can be later checked using the
+ * This method also tracks when the -no form was supplied, and if so,
+ * checks whether there was a double-negative (-nofoo=0 -> -foo=1).
+ *
+ * If there was not a double negative, it removes the "no" from the key,
+ * and returns true, indicating the caller should clear the args vector
+ * to indicate a negated option.
+ *
+ * If there was a double negative, it removes "no" from the key, sets the
+ * value to "1" and returns false.
+ *
+ * If there was no "no", it leaves key and value untouched and returns
+ * false.
+ *
+ * Where an option was negated can be later checked using the
* IsArgNegated() method. One use case for this is to have a way to disable
* options that are not normally boolean (e.g. using -nodebuglogfile to request
* that debug log output is not sent to any file at all).
*/
-void ArgsManager::InterpretNegatedOption(std::string& key, std::string& val)
+static bool InterpretNegatedOption(std::string& key, std::string& val)
{
- if (key.substr(0, 3) == "-no") {
+ assert(key[0] == '-');
+
+ size_t option_index = key.find('.');
+ if (option_index == std::string::npos) {
+ option_index = 1;
+ } else {
+ ++option_index;
+ }
+ if (key.substr(option_index, 2) == "no") {
bool bool_val = InterpretBool(val);
+ key.erase(option_index, 2);
if (!bool_val ) {
// Double negatives like -nofoo=0 are supported (but discouraged)
LogPrintf("Warning: parsed potentially confusing double-negative %s=%s\n", key, val);
+ val = "1";
+ } else {
+ return true;
}
- key.erase(1, 2);
- m_negated_args.insert(key);
- val = bool_val ? "0" : "1";
- } else {
- // In an invocation like "bitcoind -nofoo -foo" we want to unmark -foo
- // as negated when we see the second option.
- m_negated_args.erase(key);
}
+ return false;
+}
+
+ArgsManager::ArgsManager() :
+ /* These options would cause cross-contamination if values for
+ * mainnet were used while running on regtest/testnet (or vice-versa).
+ * Setting them as section_only_args ensures that sharing a config file
+ * between mainnet and regtest/testnet won't cause problems due to these
+ * parameters by accident. */
+ m_network_only_args{
+ "-addnode", "-connect",
+ "-port", "-bind",
+ "-rpcport", "-rpcbind",
+ "-wallet",
+ }
+{
+ // nothing to do
+}
+
+void ArgsManager::WarnForSectionOnlyArgs()
+{
+ // if there's no section selected, don't worry
+ if (m_network.empty()) return;
+
+ // if it's okay to use the default section for this network, don't worry
+ if (m_network == CBaseChainParams::MAIN) return;
+
+ for (const auto& arg : m_network_only_args) {
+ std::pair<bool, std::string> found_result;
+
+ // if this option is overridden it's fine
+ found_result = ArgsManagerHelper::GetArgHelper(m_override_args, arg);
+ if (found_result.first) continue;
+
+ // if there's a network-specific value for this option, it's fine
+ found_result = ArgsManagerHelper::GetArgHelper(m_config_args, ArgsManagerHelper::NetworkArg(*this, arg));
+ if (found_result.first) continue;
+
+ // if there isn't a default value for this option, it's fine
+ found_result = ArgsManagerHelper::GetArgHelper(m_config_args, arg);
+ if (!found_result.first) continue;
+
+ // otherwise, issue a warning
+ LogPrintf("Warning: Config setting for %s only applied on %s network when in [%s] section.\n", arg, m_network, m_network);
+ }
+}
+
+void ArgsManager::SelectConfigNetwork(const std::string& network)
+{
+ m_network = network;
}
void ArgsManager::ParseParameters(int argc, const char* const argv[])
{
LOCK(cs_args);
- mapArgs.clear();
- mapMultiArgs.clear();
- m_negated_args.clear();
+ m_override_args.clear();
for (int i = 1; i < argc; i++) {
std::string key(argv[i]);
@@ -510,55 +438,79 @@ void ArgsManager::ParseParameters(int argc, const char* const argv[])
if (key.length() > 1 && key[1] == '-')
key.erase(0, 1);
- // Transform -nofoo to -foo=0
- InterpretNegatedOption(key, val);
-
- mapArgs[key] = val;
- mapMultiArgs[key].push_back(val);
+ // Check for -nofoo
+ if (InterpretNegatedOption(key, val)) {
+ m_override_args[key].clear();
+ } else {
+ m_override_args[key].push_back(val);
+ }
}
}
std::vector<std::string> ArgsManager::GetArgs(const std::string& strArg) const
{
+ std::vector<std::string> result = {};
+ if (IsArgNegated(strArg)) return result; // special case
+
LOCK(cs_args);
- auto it = mapMultiArgs.find(strArg);
- if (it != mapMultiArgs.end()) return it->second;
- return {};
+
+ ArgsManagerHelper::AddArgs(result, m_override_args, strArg);
+ if (!m_network.empty()) {
+ ArgsManagerHelper::AddArgs(result, m_config_args, ArgsManagerHelper::NetworkArg(*this, strArg));
+ }
+
+ if (ArgsManagerHelper::UseDefaultSection(*this, strArg)) {
+ ArgsManagerHelper::AddArgs(result, m_config_args, strArg);
+ }
+
+ return result;
}
bool ArgsManager::IsArgSet(const std::string& strArg) const
{
- LOCK(cs_args);
- return mapArgs.count(strArg);
+ if (IsArgNegated(strArg)) return true; // special case
+ return ArgsManagerHelper::GetArg(*this, strArg).first;
}
bool ArgsManager::IsArgNegated(const std::string& strArg) const
{
LOCK(cs_args);
- return m_negated_args.find(strArg) != m_negated_args.end();
+
+ const auto& ov = m_override_args.find(strArg);
+ if (ov != m_override_args.end()) return ov->second.empty();
+
+ if (!m_network.empty()) {
+ const auto& cfs = m_config_args.find(ArgsManagerHelper::NetworkArg(*this, strArg));
+ if (cfs != m_config_args.end()) return cfs->second.empty();
+ }
+
+ const auto& cf = m_config_args.find(strArg);
+ if (cf != m_config_args.end()) return cf->second.empty();
+
+ return false;
}
std::string ArgsManager::GetArg(const std::string& strArg, const std::string& strDefault) const
{
- LOCK(cs_args);
- auto it = mapArgs.find(strArg);
- if (it != mapArgs.end()) return it->second;
+ if (IsArgNegated(strArg)) return "0";
+ std::pair<bool,std::string> found_res = ArgsManagerHelper::GetArg(*this, strArg);
+ if (found_res.first) return found_res.second;
return strDefault;
}
int64_t ArgsManager::GetArg(const std::string& strArg, int64_t nDefault) const
{
- LOCK(cs_args);
- auto it = mapArgs.find(strArg);
- if (it != mapArgs.end()) return atoi64(it->second);
+ if (IsArgNegated(strArg)) return 0;
+ std::pair<bool,std::string> found_res = ArgsManagerHelper::GetArg(*this, strArg);
+ if (found_res.first) return atoi64(found_res.second);
return nDefault;
}
bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault) const
{
- LOCK(cs_args);
- auto it = mapArgs.find(strArg);
- if (it != mapArgs.end()) return InterpretBool(it->second);
+ if (IsArgNegated(strArg)) return false;
+ std::pair<bool,std::string> found_res = ArgsManagerHelper::GetArg(*this, strArg);
+ if (found_res.first) return InterpretBool(found_res.second);
return fDefault;
}
@@ -581,8 +533,7 @@ bool ArgsManager::SoftSetBoolArg(const std::string& strArg, bool fValue)
void ArgsManager::ForceSetArg(const std::string& strArg, const std::string& strValue)
{
LOCK(cs_args);
- mapArgs[strArg] = strValue;
- mapMultiArgs[strArg] = {strValue};
+ m_override_args[strArg] = {strValue};
}
bool HelpRequested(const ArgsManager& args)
@@ -745,18 +696,23 @@ void ArgsManager::ReadConfigStream(std::istream& stream)
for (boost::program_options::detail::config_file_iterator it(stream, setOptions), end; it != end; ++it)
{
- // Don't overwrite existing settings so command line settings override bitcoin.conf
std::string strKey = std::string("-") + it->string_key;
std::string strValue = it->value[0];
- InterpretNegatedOption(strKey, strValue);
- if (mapArgs.count(strKey) == 0)
- mapArgs[strKey] = strValue;
- mapMultiArgs[strKey].push_back(strValue);
+ if (InterpretNegatedOption(strKey, strValue)) {
+ m_config_args[strKey].clear();
+ } else {
+ m_config_args[strKey].push_back(strValue);
+ }
}
}
void ArgsManager::ReadConfigFile(const std::string& confPath)
{
+ {
+ LOCK(cs_args);
+ m_config_args.clear();
+ }
+
fs::ifstream stream(GetConfigFile(confPath));
// ok to not have a config file
@@ -773,8 +729,8 @@ void ArgsManager::ReadConfigFile(const std::string& confPath)
std::string ArgsManager::GetChainName() const
{
- bool fRegTest = GetBoolArg("-regtest", false);
- bool fTestNet = GetBoolArg("-testnet", false);
+ bool fRegTest = ArgsManagerHelper::GetNetBoolArg(*this, "-regtest");
+ bool fTestNet = ArgsManagerHelper::GetNetBoolArg(*this, "-testnet");
if (fTestNet && fRegTest)
throw std::runtime_error("Invalid combination of -regtest and -testnet.");
@@ -926,34 +882,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");
- // 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 && fs::file_size(pathLog) > 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 18d2076a05..6e742f8b91 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>
@@ -24,6 +25,7 @@
#include <exception>
#include <map>
#include <memory>
+#include <set>
#include <stdint.h>
#include <string>
#include <unordered_set>
@@ -35,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
{
@@ -48,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.
@@ -75,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)
{
@@ -198,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);
/**
@@ -225,18 +121,36 @@ inline bool IsSwitchChar(char c)
class ArgsManager
{
protected:
+ friend class ArgsManagerHelper;
+
mutable CCriticalSection cs_args;
- std::map<std::string, std::string> mapArgs;
- std::map<std::string, std::vector<std::string>> mapMultiArgs;
- std::unordered_set<std::string> m_negated_args;
+ std::map<std::string, std::vector<std::string>> m_override_args;
+ std::map<std::string, std::vector<std::string>> m_config_args;
+ std::string m_network;
+ std::set<std::string> m_network_only_args;
void ReadConfigStream(std::istream& stream);
public:
+ ArgsManager();
+
+ /**
+ * Select the network in use
+ */
+ void SelectConfigNetwork(const std::string& network);
+
void ParseParameters(int argc, const char*const argv[]);
void ReadConfigFile(const std::string& confPath);
/**
+ * Log warnings for options in m_section_only_args when
+ * they are specified in the default section but not overridden
+ * on the command line or in a network-specific section in the
+ * config file.
+ */
+ void WarnForSectionOnlyArgs();
+
+ /**
* Return a vector of strings of the given argument
*
* @param strArg Argument to get (e.g. "-foo")
@@ -315,11 +229,6 @@ public:
* @return CBaseChainParams::MAIN by default; raises runtime error if an invalid combination is given.
*/
std::string GetChainName() const;
-
-private:
-
- // Munge -nofoo into -foo=0 and track the value as negated.
- void InterpretNegatedOption(std::string &key, std::string &val);
};
extern ArgsManager gArgs;
diff --git a/src/validation.cpp b/src/validation.cpp
index 958c187220..daa33d3f5a 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -354,7 +354,7 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool
CBlockIndex* tip = chainActive.Tip();
assert(tip != nullptr);
-
+
CBlockIndex index;
index.pprev = tip;
// CheckSequenceLocks() uses chainActive.Height()+1 to evaluate
@@ -1726,16 +1726,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 +1773,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;
}
@@ -2678,18 +2698,17 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
assert(trace.pblock && trace.pindex);
GetMainSignals().BlockConnected(trace.pblock, trace.pindex, trace.conflictedTxs);
}
- }
- // When we reach this point, we switched to a new tip (stored in pindexNewTip).
-
- // Notifications/callbacks that can run without cs_main
- // Notify external listeners about the new tip.
- GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
+ // Notify external listeners about the new tip.
+ // Enqueue while holding cs_main to ensure that UpdatedBlockTip is called in the order in which blocks are connected
+ GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
- // Always notify the UI if a new block tip was connected
- if (pindexFork != pindexNewTip) {
- uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip);
+ // Always notify the UI if a new block tip was connected
+ if (pindexFork != pindexNewTip) {
+ uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip);
+ }
}
+ // When we reach this point, we switched to a new tip (stored in pindexNewTip).
if (nStopAtHeight && pindexNewTip && pindexNewTip->nHeight >= nStopAtHeight) StartShutdown();
@@ -3100,6 +3119,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)
@@ -4092,6 +4117,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;
}
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/validationinterface.cpp b/src/validationinterface.cpp
index 928df4fa65..746263f113 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -139,6 +139,10 @@ void CMainSignals::MempoolEntryRemoved(CTransactionRef ptx, MemPoolRemovalReason
}
void CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
+ // Dependencies exist that require UpdatedBlockTip events to be delivered in the order in which
+ // the chain actually updates. One way to ensure this is for the caller to invoke this signal
+ // in the same critical section where the chain is updated
+
m_internals->m_schedulerClient.AddToProcessQueue([pindexNew, pindexFork, fInitialDownload, this] {
m_internals->UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload);
});
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index b6f4a0e1e1..2fd9aa1a6f 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -18,39 +18,38 @@ class WalletInit : public WalletInitInterface {
public:
//! Return the wallets help message.
- std::string GetHelpString(bool showDebug) override;
+ std::string GetHelpString(bool showDebug) const override;
//! Wallets parameter interaction
- bool ParameterInteraction() override;
+ bool ParameterInteraction() const override;
//! Register wallet RPCs.
- void RegisterRPC(CRPCTable &tableRPC) override;
+ 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() override;
+ bool Verify() const override;
//! Load wallet databases.
- bool Open() override;
+ bool Open() const override;
//! Complete startup of wallets.
- void Start(CScheduler& scheduler) override;
+ void Start(CScheduler& scheduler) const override;
//! Flush all wallets in preparation for shutdown.
- void Flush() override;
+ void Flush() const override;
//! Stop all wallets. Wallets will be flushed first.
- void Stop() override;
+ void Stop() const override;
//! Close all wallets.
- void Close() override;
+ void Close() const override;
};
-static WalletInit g_wallet_init;
-WalletInitInterface* const g_wallet_init_interface = &g_wallet_init;
+const WalletInitInterface& g_wallet_init_interface = WalletInit();
-std::string WalletInit::GetHelpString(bool showDebug)
+std::string WalletInit::GetHelpString(bool showDebug) const
{
std::string strUsage = HelpMessageGroup(_("Wallet options:"));
strUsage += HelpMessageOpt("-addresstype", strprintf("What type of addresses to use (\"legacy\", \"p2sh-segwit\", or \"bech32\", default: \"%s\")", FormatOutputType(DEFAULT_ADDRESS_TYPE)));
@@ -92,7 +91,7 @@ std::string WalletInit::GetHelpString(bool showDebug)
return strUsage;
}
-bool WalletInit::ParameterInteraction()
+bool WalletInit::ParameterInteraction() const
{
if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
for (const std::string& wallet : gArgs.GetArgs("-wallet")) {
@@ -220,7 +219,7 @@ bool WalletInit::ParameterInteraction()
return true;
}
-void WalletInit::RegisterRPC(CRPCTable &t)
+void WalletInit::RegisterRPC(CRPCTable &t) const
{
if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
return;
@@ -229,7 +228,7 @@ void WalletInit::RegisterRPC(CRPCTable &t)
RegisterWalletRPCCommands(t);
}
-bool WalletInit::Verify()
+bool WalletInit::Verify() const
{
if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
return true;
@@ -304,7 +303,7 @@ bool WalletInit::Verify()
return true;
}
-bool WalletInit::Open()
+bool WalletInit::Open() const
{
if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
LogPrintf("Wallet disabled!\n");
@@ -322,28 +321,28 @@ bool WalletInit::Open()
return true;
}
-void WalletInit::Start(CScheduler& scheduler)
+void WalletInit::Start(CScheduler& scheduler) const
{
for (CWalletRef pwallet : vpwallets) {
pwallet->postInitProcess(scheduler);
}
}
-void WalletInit::Flush()
+void WalletInit::Flush() const
{
for (CWalletRef pwallet : vpwallets) {
pwallet->Flush(false);
}
}
-void WalletInit::Stop()
+void WalletInit::Stop() const
{
for (CWalletRef pwallet : vpwallets) {
pwallet->Flush(true);
}
}
-void WalletInit::Close()
+void WalletInit::Close() const
{
for (CWalletRef pwallet : vpwallets) {
delete pwallet;
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 14c5ad7214..57705926a3 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -119,14 +119,14 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
// will pick up both blocks, not just the first.
const int64_t BLOCK_TIME = chainActive.Tip()->GetBlockTimeMax() + 5;
SetMockTime(BLOCK_TIME);
- coinbaseTxns.emplace_back(*CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
- coinbaseTxns.emplace_back(*CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
+ m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
+ m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
// Set key birthday to block time increased by the timestamp window, so
// rescan will start at the block time.
const int64_t KEY_TIME = BLOCK_TIME + TIMESTAMP_WINDOW;
SetMockTime(KEY_TIME);
- coinbaseTxns.emplace_back(*CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
+ m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
LOCK(cs_main);
@@ -142,6 +142,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
request.params.push_back((pathTemp / "wallet.backup").string());
vpwallets.insert(vpwallets.begin(), &wallet);
::dumpwallet(request);
+ vpwallets.erase(vpwallets.begin());
}
// Call importwallet RPC and verify all blocks with timestamps >= BLOCK_TIME
@@ -152,21 +153,21 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
JSONRPCRequest request;
request.params.setArray();
request.params.push_back((pathTemp / "wallet.backup").string());
- vpwallets[0] = &wallet;
+ vpwallets.insert(vpwallets.begin(), &wallet);
::importwallet(request);
+ vpwallets.erase(vpwallets.begin());
LOCK(wallet.cs_wallet);
BOOST_CHECK_EQUAL(wallet.mapWallet.size(), 3U);
- BOOST_CHECK_EQUAL(coinbaseTxns.size(), 103U);
- for (size_t i = 0; i < coinbaseTxns.size(); ++i) {
- bool found = wallet.GetWalletTx(coinbaseTxns[i].GetHash());
+ BOOST_CHECK_EQUAL(m_coinbase_txns.size(), 103U);
+ for (size_t i = 0; i < m_coinbase_txns.size(); ++i) {
+ bool found = wallet.GetWalletTx(m_coinbase_txns[i]->GetHash());
bool expected = i >= 100;
BOOST_CHECK_EQUAL(found, expected);
}
}
SetMockTime(0);
- vpwallets.erase(vpwallets.begin());
}
// Check that GetImmatureCredit() returns a newly calculated value instead of
@@ -178,7 +179,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
{
CWallet wallet("dummy", WalletDatabase::CreateDummy());
- CWalletTx wtx(&wallet, MakeTransactionRef(coinbaseTxns.back()));
+ CWalletTx wtx(&wallet, m_coinbase_txns.back());
LOCK2(cs_main, wallet.cs_wallet);
wtx.hashBlock = chainActive.Tip()->GetBlockHash();
wtx.nIndex = 0;
diff --git a/src/walletinitinterface.h b/src/walletinitinterface.h
index c7eee37ce5..5bfde6faaf 100644
--- a/src/walletinitinterface.h
+++ b/src/walletinitinterface.h
@@ -13,23 +13,23 @@ class CRPCTable;
class WalletInitInterface {
public:
/** Get wallet help string */
- virtual std::string GetHelpString(bool showDebug) = 0;
+ virtual std::string GetHelpString(bool showDebug) const = 0;
/** Check wallet parameter interaction */
- virtual bool ParameterInteraction() = 0;
+ virtual bool ParameterInteraction() const = 0;
/** Register wallet RPC*/
- virtual void RegisterRPC(CRPCTable &) = 0;
+ virtual void RegisterRPC(CRPCTable &) const = 0;
/** Verify wallets */
- virtual bool Verify() = 0;
+ virtual bool Verify() const = 0;
/** Open wallets*/
- virtual bool Open() = 0;
+ virtual bool Open() const = 0;
/** Start wallets*/
- virtual void Start(CScheduler& scheduler) = 0;
+ virtual void Start(CScheduler& scheduler) const = 0;
/** Flush Wallets*/
- virtual void Flush() = 0;
+ virtual void Flush() const = 0;
/** Stop Wallets*/
- virtual void Stop() = 0;
+ virtual void Stop() const = 0;
/** Close wallets */
- virtual void Close() = 0;
+ virtual void Close() const = 0;
virtual ~WalletInitInterface() {}
};