aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.test.include7
-rw-r--r--src/base58.cpp4
-rw-r--r--src/base58.h13
-rw-r--r--src/bitcoind.cpp40
-rw-r--r--src/chain.h6
-rw-r--r--src/compat.h3
-rw-r--r--src/hash.cpp7
-rw-r--r--src/hash.h31
-rw-r--r--src/index/base.cpp9
-rw-r--r--src/index/base.h16
-rw-r--r--src/index/disktxpos.h4
-rw-r--r--src/index/txindex.cpp12
-rw-r--r--src/init.cpp329
-rw-r--r--src/init.h10
-rw-r--r--src/interfaces/node.cpp21
-rw-r--r--src/interfaces/node.h38
-rw-r--r--src/interfaces/wallet.cpp7
-rw-r--r--src/net.cpp2
-rw-r--r--src/net.h2
-rw-r--r--src/net_processing.cpp364
-rw-r--r--src/net_processing.h13
-rw-r--r--src/netaddress.cpp475
-rw-r--r--src/netaddress.h156
-rw-r--r--src/netbase.cpp5
-rw-r--r--src/qt/bitcoin.cpp80
-rw-r--r--src/qt/bitcoin.h10
-rw-r--r--src/qt/bitcoingui.cpp4
-rw-r--r--src/qt/forms/debugwindow.ui2
-rw-r--r--src/qt/forms/receivecoinsdialog.ui6
-rw-r--r--src/qt/guiutil.cpp5
-rw-r--r--src/qt/intro.cpp9
-rw-r--r--src/qt/intro.h2
-rw-r--r--src/qt/optionsmodel.cpp26
-rw-r--r--src/qt/optionsmodel.h9
-rw-r--r--src/qt/paymentserver.cpp6
-rw-r--r--src/qt/paymentserver.h2
-rw-r--r--src/qt/receivecoinsdialog.cpp16
-rw-r--r--src/qt/receivecoinsdialog.h3
-rw-r--r--src/qt/splashscreen.cpp31
-rw-r--r--src/qt/splashscreen.h8
-rw-r--r--src/qt/test/addressbooktests.cpp2
-rw-r--r--src/qt/test/test_main.cpp12
-rw-r--r--src/qt/test/wallettests.cpp2
-rw-r--r--src/qt/utilitydialog.cpp2
-rw-r--r--src/qt/utilitydialog.h6
-rw-r--r--src/rpc/blockchain.cpp8
-rw-r--r--src/rpc/mining.cpp19
-rw-r--r--src/rpc/misc.cpp57
-rw-r--r--src/rpc/net.cpp6
-rw-r--r--src/rpc/rawtransaction.cpp10
-rw-r--r--src/script/interpreter.cpp27
-rw-r--r--src/support/lockedpool.cpp1
-rw-r--r--src/test/denialofservice_tests.cpp28
-rw-r--r--src/test/fuzz/asmap.cpp14
-rw-r--r--src/test/fuzz/net.cpp156
-rw-r--r--src/test/fuzz/netaddress.cpp5
-rw-r--r--src/test/fuzz/process_message.cpp19
-rw-r--r--src/test/fuzz/util.h2
-rw-r--r--src/test/net_tests.cpp74
-rw-r--r--src/test/netbase_tests.cpp17
-rw-r--r--src/test/util/setup_common.cpp41
-rw-r--r--src/test/util/setup_common.h13
-rw-r--r--src/threadsafety.h6
-rw-r--r--src/util/message.cpp2
-rw-r--r--src/util/strencodings.cpp28
-rw-r--r--src/util/strencodings.h11
-rw-r--r--src/util/system.cpp6
-rw-r--r--src/wallet/rpcwallet.cpp9
-rw-r--r--src/wallet/wallet.cpp55
-rw-r--r--src/wallet/wallet.h18
70 files changed, 1437 insertions, 1012 deletions
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 0068c94070..a0c9c30f36 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -70,6 +70,7 @@ FUZZ_TARGETS = \
test/fuzz/message \
test/fuzz/messageheader_deserialize \
test/fuzz/multiplication_overflow \
+ test/fuzz/net \
test/fuzz/net_permissions \
test/fuzz/netaddr_deserialize \
test/fuzz/netaddress \
@@ -722,6 +723,12 @@ test_fuzz_multiplication_overflow_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_multiplication_overflow_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
test_fuzz_multiplication_overflow_SOURCES = test/fuzz/multiplication_overflow.cpp
+test_fuzz_net_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+test_fuzz_net_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_net_LDADD = $(FUZZ_SUITE_LD_COMMON)
+test_fuzz_net_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_net_SOURCES = test/fuzz/net.cpp
+
test_fuzz_net_permissions_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_net_permissions_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_net_permissions_LDADD = $(FUZZ_SUITE_LD_COMMON)
diff --git a/src/base58.cpp b/src/base58.cpp
index 18cd2090e0..0dc6044145 100644
--- a/src/base58.cpp
+++ b/src/base58.cpp
@@ -35,7 +35,7 @@ static const int8_t mapBase58[256] = {
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
};
-bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch, int max_ret_len)
+NODISCARD static bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch, int max_ret_len)
{
// Skip leading spaces.
while (*psz && IsSpace(*psz))
@@ -141,7 +141,7 @@ std::string EncodeBase58Check(Span<const unsigned char> input)
return EncodeBase58(vch);
}
-bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet, int max_ret_len)
+NODISCARD static bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet, int max_ret_len)
{
if (!DecodeBase58(psz, vchRet, max_ret_len > std::numeric_limits<int>::max() - 4 ? std::numeric_limits<int>::max() : max_ret_len + 4) ||
(vchRet.size() < 4)) {
diff --git a/src/base58.h b/src/base58.h
index b87664b78b..468c3e2589 100644
--- a/src/base58.h
+++ b/src/base58.h
@@ -26,13 +26,6 @@
std::string EncodeBase58(Span<const unsigned char> input);
/**
- * Decode a base58-encoded string (psz) into a byte vector (vchRet).
- * return true if decoding is successful.
- * psz cannot be nullptr.
- */
-NODISCARD bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet, int max_ret_len);
-
-/**
* Decode a base58-encoded string (str) into a byte vector (vchRet).
* return true if decoding is successful.
*/
@@ -44,12 +37,6 @@ NODISCARD bool DecodeBase58(const std::string& str, std::vector<unsigned char>&
std::string EncodeBase58Check(Span<const unsigned char> input);
/**
- * Decode a base58-encoded string (psz) that includes a checksum into a byte
- * vector (vchRet), return true if decoding is successful
- */
-NODISCARD bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet, int max_ret_len);
-
-/**
* Decode a base58-encoded string (str) that includes a checksum into a byte
* vector (vchRet), return true if decoding is successful
*/
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index b04cc12059..227626f40f 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -50,28 +50,23 @@ static bool AppInit(int argc, char* argv[])
util::ThreadSetInternalName("init");
- //
- // Parameters
- //
// If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
SetupServerArgs(node);
+ ArgsManager& args = *Assert(node.args);
std::string error;
- if (!gArgs.ParseParameters(argc, argv, error)) {
+ if (!args.ParseParameters(argc, argv, error)) {
return InitError(Untranslated(strprintf("Error parsing command line arguments: %s\n", error)));
}
// Process help and version before taking care about datadir
- if (HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
+ if (HelpRequested(args) || args.IsArgSet("-version")) {
std::string strUsage = PACKAGE_NAME " version " + FormatFullVersion() + "\n";
- if (gArgs.IsArgSet("-version"))
- {
+ if (args.IsArgSet("-version")) {
strUsage += FormatParagraph(LicenseInfo()) + "\n";
- }
- else
- {
+ } else {
strUsage += "\nUsage: bitcoind [options] Start " PACKAGE_NAME "\n";
- strUsage += "\n" + gArgs.GetHelpMessage();
+ strUsage += "\n" + args.GetHelpMessage();
}
tfm::format(std::cout, "%s", strUsage);
@@ -82,14 +77,14 @@ static bool AppInit(int argc, char* argv[])
try
{
if (!CheckDataDirOption()) {
- return InitError(Untranslated(strprintf("Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", ""))));
+ return InitError(Untranslated(strprintf("Specified data directory \"%s\" does not exist.\n", args.GetArg("-datadir", ""))));
}
- if (!gArgs.ReadConfigFiles(error, true)) {
+ if (!args.ReadConfigFiles(error, true)) {
return InitError(Untranslated(strprintf("Error reading configuration file: %s\n", error)));
}
// Check for -chain, -testnet or -regtest parameter (Params() calls are only valid after this clause)
try {
- SelectParams(gArgs.GetChainName());
+ SelectParams(args.GetChainName());
} catch (const std::exception& e) {
return InitError(Untranslated(strprintf("%s\n", e.what())));
}
@@ -101,23 +96,21 @@ static bool AppInit(int argc, char* argv[])
}
}
- if (!gArgs.InitSettings(error)) {
+ if (!args.InitSettings(error)) {
InitError(Untranslated(error));
return false;
}
// -server defaults to true for bitcoind but not for the GUI so do this here
- gArgs.SoftSetBoolArg("-server", true);
+ args.SoftSetBoolArg("-server", true);
// Set this early so that parameter interactions go to console
- InitLogging();
- InitParameterInteraction();
- if (!AppInitBasicSetup())
- {
+ InitLogging(args);
+ InitParameterInteraction(args);
+ if (!AppInitBasicSetup(args)) {
// InitError will have been called with detailed error, which ends up on console
return false;
}
- if (!AppInitParameterInteraction())
- {
+ if (!AppInitParameterInteraction(args)) {
// InitError will have been called with detailed error, which ends up on console
return false;
}
@@ -126,8 +119,7 @@ static bool AppInit(int argc, char* argv[])
// InitError will have been called with detailed error, which ends up on console
return false;
}
- if (gArgs.GetBoolArg("-daemon", false))
- {
+ if (args.GetBoolArg("-daemon", false)) {
#if HAVE_DECL_DAEMON
#if defined(MAC_OSX)
#pragma GCC diagnostic push
diff --git a/src/chain.h b/src/chain.h
index 802e23f775..43e8a39f36 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -398,12 +398,6 @@ public:
return vChain[nHeight];
}
- /** Compare two chains efficiently. */
- friend bool operator==(const CChain &a, const CChain &b) {
- return a.vChain.size() == b.vChain.size() &&
- a.vChain[a.vChain.size() - 1] == b.vChain[b.vChain.size() - 1];
- }
-
/** Efficiently check whether a block is present in this chain. */
bool Contains(const CBlockIndex *pindex) const {
return (*this)[pindex->nHeight] == pindex;
diff --git a/src/compat.h b/src/compat.h
index 68f6eb692c..0be02cae03 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -11,9 +11,6 @@
#endif
#ifdef WIN32
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN 1
-#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
diff --git a/src/hash.cpp b/src/hash.cpp
index 4c09f5f646..83b90ae063 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -77,3 +77,10 @@ void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char he
num[3] = (nChild >> 0) & 0xFF;
CHMAC_SHA512(chainCode.begin(), chainCode.size()).Write(&header, 1).Write(data, 32).Write(num, 4).Finalize(output);
}
+
+uint256 SHA256Uint256(const uint256& input)
+{
+ uint256 result;
+ CSHA256().Write(input.begin(), 32).Finalize(result.begin());
+ return result;
+}
diff --git a/src/hash.h b/src/hash.h
index 71806483ff..c16bbb48ce 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -6,6 +6,7 @@
#ifndef BITCOIN_HASH_H
#define BITCOIN_HASH_H
+#include <attributes.h>
#include <crypto/common.h>
#include <crypto/ripemd160.h>
#include <crypto/sha256.h>
@@ -98,7 +99,7 @@ inline uint160 Hash160(const T1& in1)
class CHashWriter
{
private:
- CHash256 ctx;
+ CSHA256 ctx;
const int nType;
const int nVersion;
@@ -110,13 +111,27 @@ public:
int GetVersion() const { return nVersion; }
void write(const char *pch, size_t size) {
- ctx.Write({(const unsigned char*)pch, size});
+ ctx.Write((const unsigned char*)pch, size);
}
- // invalidates the object
+ /** Compute the double-SHA256 hash of all data written to this object.
+ *
+ * Invalidates this object.
+ */
uint256 GetHash() {
uint256 result;
- ctx.Finalize(result);
+ ctx.Finalize(result.begin());
+ ctx.Reset().Write(result.begin(), CSHA256::OUTPUT_SIZE).Finalize(result.begin());
+ return result;
+ }
+
+ /** Compute the SHA256 hash of all data written to this object.
+ *
+ * Invalidates this object.
+ */
+ uint256 GetSHA256() {
+ uint256 result;
+ ctx.Finalize(result.begin());
return result;
}
@@ -124,9 +139,8 @@ public:
* Returns the first 64 bits from the resulting hash.
*/
inline uint64_t GetCheapHash() {
- unsigned char result[CHash256::OUTPUT_SIZE];
- ctx.Finalize(result);
- return ReadLE64(result);
+ uint256 result = GetHash();
+ return ReadLE64(result.begin());
}
template<typename T>
@@ -181,6 +195,9 @@ uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL
return ss.GetHash();
}
+/** Single-SHA256 a 32-byte input (represented as uint256). */
+NODISCARD uint256 SHA256Uint256(const uint256& input);
+
unsigned int MurmurHash3(unsigned int nHashSeed, Span<const unsigned char> vDataToHash);
void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]);
diff --git a/src/index/base.cpp b/src/index/base.cpp
index f587205a28..e67b813763 100644
--- a/src/index/base.cpp
+++ b/src/index/base.cpp
@@ -319,3 +319,12 @@ void BaseIndex::Stop()
m_thread_sync.join();
}
}
+
+IndexSummary BaseIndex::GetSummary() const
+{
+ IndexSummary summary{};
+ summary.name = GetName();
+ summary.synced = m_synced;
+ summary.best_block_height = m_best_block_index.load()->nHeight;
+ return summary;
+}
diff --git a/src/index/base.h b/src/index/base.h
index 3fab810bb2..8559e3cb64 100644
--- a/src/index/base.h
+++ b/src/index/base.h
@@ -13,6 +13,12 @@
class CBlockIndex;
+struct IndexSummary {
+ std::string name;
+ bool synced{false};
+ int best_block_height{0};
+};
+
/**
* Base class for indices of blockchain data. This implements
* CValidationInterface and ensures blocks are indexed sequentially according
@@ -21,6 +27,13 @@ class CBlockIndex;
class BaseIndex : public CValidationInterface
{
protected:
+ /**
+ * The database stores a block locator of the chain the database is synced to
+ * so that the index can efficiently determine the point it last stopped at.
+ * A locator is used instead of a simple hash of the chain tip because blocks
+ * and block index entries may not be flushed to disk until after this database
+ * is updated.
+ */
class DB : public CDBWrapper
{
public:
@@ -106,6 +119,9 @@ public:
/// Stops the instance from staying in sync with blockchain updates.
void Stop();
+
+ /// Get a summary of the index and its state.
+ IndexSummary GetSummary() const;
};
#endif // BITCOIN_INDEX_BASE_H
diff --git a/src/index/disktxpos.h b/src/index/disktxpos.h
index 8cd2270028..69696b0ec5 100644
--- a/src/index/disktxpos.h
+++ b/src/index/disktxpos.h
@@ -5,10 +5,8 @@
#ifndef BITCOIN_INDEX_DISKTXPOS_H
#define BITCOIN_INDEX_DISKTXPOS_H
-#include <chain.h>
#include <flatfile.h>
-#include <primitives/block.h>
-#include <primitives/transaction.h>
+#include <serialize.h>
struct CDiskTxPos : public FlatFilePos
{
diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp
index 104b05d4ba..462ac5962f 100644
--- a/src/index/txindex.cpp
+++ b/src/index/txindex.cpp
@@ -16,15 +16,9 @@ constexpr char DB_TXINDEX_BLOCK = 'T';
std::unique_ptr<TxIndex> g_txindex;
-/**
- * Access to the txindex database (indexes/txindex/)
- *
- * The database stores a block locator of the chain the database is synced to
- * so that the TxIndex can efficiently determine the point it last stopped at.
- * A locator is used instead of a simple hash of the chain tip because blocks
- * and block index entries may not be flushed to disk until after this database
- * is updated.
- */
+
+
+/** Access to the txindex database (indexes/txindex/) */
class TxIndex::DB : public BaseIndex::DB
{
public:
diff --git a/src/init.cpp b/src/init.cpp
index f5aef08211..ecd57960ad 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -107,14 +107,14 @@ static const char* DEFAULT_ASMAP_FILENAME="ip_asn.map";
*/
static const char* BITCOIN_PID_FILENAME = "bitcoind.pid";
-static fs::path GetPidFile()
+static fs::path GetPidFile(const ArgsManager& args)
{
- return AbsPathForConfigVal(fs::path(gArgs.GetArg("-pid", BITCOIN_PID_FILENAME)));
+ return AbsPathForConfigVal(fs::path(args.GetArg("-pid", BITCOIN_PID_FILENAME)));
}
-NODISCARD static bool CreatePidFile()
+NODISCARD static bool CreatePidFile(const ArgsManager& args)
{
- fsbridge::ofstream file{GetPidFile()};
+ fsbridge::ofstream file{GetPidFile(args)};
if (file) {
#ifdef WIN32
tfm::format(file, "%d\n", GetCurrentProcessId());
@@ -123,7 +123,7 @@ NODISCARD static bool CreatePidFile()
#endif
return true;
} else {
- return InitError(strprintf(_("Unable to create the PID file '%s': %s"), GetPidFile().string(), std::strerror(errno)));
+ return InitError(strprintf(_("Unable to create the PID file '%s': %s"), GetPidFile(args).string(), std::strerror(errno)));
}
}
@@ -180,6 +180,7 @@ void Shutdown(NodeContext& node)
TRY_LOCK(g_shutdown_mutex, lock_shutdown);
if (!lock_shutdown) return;
LogPrintf("%s: In progress...\n", __func__);
+ Assert(node.args);
/// Note: Shutdown() must be able to handle cases in which initialization failed part of the way,
/// for example if the data directory was found to be locked.
@@ -230,7 +231,7 @@ void Shutdown(NodeContext& node)
node.connman.reset();
node.banman.reset();
- if (::mempool.IsLoaded() && gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
+ if (::mempool.IsLoaded() && node.args->GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
DumpMempool(::mempool);
}
@@ -301,19 +302,19 @@ void Shutdown(NodeContext& node)
GetMainSignals().UnregisterBackgroundSignalScheduler();
globalVerifyHandle.reset();
ECC_Stop();
- node.args = nullptr;
node.mempool = nullptr;
node.chainman = nullptr;
node.scheduler.reset();
try {
- if (!fs::remove(GetPidFile())) {
+ if (!fs::remove(GetPidFile(*node.args))) {
LogPrintf("%s: Unable to remove PID file: File does not exist\n", __func__);
}
} catch (const fs::filesystem_error& e) {
LogPrintf("%s: Unable to remove PID file: %s\n", __func__, fsbridge::get_filesystem_error_message(e));
}
+ node.args = nullptr;
LogPrintf("%s: done\n", __func__);
}
@@ -372,7 +373,7 @@ void SetupServerArgs(NodeContext& node)
node.args = &gArgs;
ArgsManager& argsman = *node.args;
- SetupHelpOptions(gArgs);
+ SetupHelpOptions(argsman);
argsman.AddArg("-help-debug", "Print help message with debugging options and exit", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); // server-only for now
const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN);
@@ -599,21 +600,6 @@ std::string LicenseInfo()
"\n";
}
-#if HAVE_SYSTEM
-static void BlockNotifyCallback(SynchronizationState sync_state, const CBlockIndex* pBlockIndex)
-{
- if (sync_state != SynchronizationState::POST_INIT || !pBlockIndex)
- return;
-
- std::string strCmd = gArgs.GetArg("-blocknotify", "");
- if (!strCmd.empty()) {
- boost::replace_all(strCmd, "%s", pBlockIndex->GetBlockHash().GetHex());
- std::thread t(runCommand, strCmd);
- t.detach(); // thread runs free
- }
-}
-#endif
-
static bool fHaveGenesis = false;
static Mutex g_genesis_wait_mutex;
static std::condition_variable g_genesis_wait_cv;
@@ -684,7 +670,7 @@ static void CleanupBlockRevFiles()
}
}
-static void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFiles)
+static void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFiles, const ArgsManager& args)
{
const CChainParams& chainparams = Params();
ScheduleBatchPriority();
@@ -746,13 +732,13 @@ static void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImp
}
}
- if (gArgs.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) {
+ if (args.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) {
LogPrintf("Stopping after block import\n");
StartShutdown();
return;
}
} // End scope of CImportingNow
- if (gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
+ if (args.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
LoadMempool(::mempool);
}
::mempool.SetIsLoaded(!ShutdownRequested());
@@ -780,6 +766,7 @@ static bool InitSanityCheck()
static bool AppInitServers(const util::Ref& context, NodeContext& node)
{
+ const ArgsManager& args = *Assert(node.args);
RPCServer::OnStarted(&OnRPCStarted);
RPCServer::OnStopped(&OnRPCStopped);
if (!InitHTTPServer())
@@ -788,71 +775,71 @@ static bool AppInitServers(const util::Ref& context, NodeContext& node)
node.rpc_interruption_point = RpcInterruptionPoint;
if (!StartHTTPRPC(context))
return false;
- if (gArgs.GetBoolArg("-rest", DEFAULT_REST_ENABLE)) StartREST(context);
+ if (args.GetBoolArg("-rest", DEFAULT_REST_ENABLE)) StartREST(context);
StartHTTPServer();
return true;
}
// Parameter interaction based on rules
-void InitParameterInteraction()
+void InitParameterInteraction(ArgsManager& args)
{
// when specifying an explicit binding address, you want to listen on it
// even when -connect or -proxy is specified
- if (gArgs.IsArgSet("-bind")) {
- if (gArgs.SoftSetBoolArg("-listen", true))
+ if (args.IsArgSet("-bind")) {
+ if (args.SoftSetBoolArg("-listen", true))
LogPrintf("%s: parameter interaction: -bind set -> setting -listen=1\n", __func__);
}
- if (gArgs.IsArgSet("-whitebind")) {
- if (gArgs.SoftSetBoolArg("-listen", true))
+ if (args.IsArgSet("-whitebind")) {
+ if (args.SoftSetBoolArg("-listen", true))
LogPrintf("%s: parameter interaction: -whitebind set -> setting -listen=1\n", __func__);
}
- if (gArgs.IsArgSet("-connect")) {
+ if (args.IsArgSet("-connect")) {
// when only connecting to trusted nodes, do not seed via DNS, or listen by default
- if (gArgs.SoftSetBoolArg("-dnsseed", false))
+ if (args.SoftSetBoolArg("-dnsseed", false))
LogPrintf("%s: parameter interaction: -connect set -> setting -dnsseed=0\n", __func__);
- if (gArgs.SoftSetBoolArg("-listen", false))
+ if (args.SoftSetBoolArg("-listen", false))
LogPrintf("%s: parameter interaction: -connect set -> setting -listen=0\n", __func__);
}
- if (gArgs.IsArgSet("-proxy")) {
+ if (args.IsArgSet("-proxy")) {
// to protect privacy, do not listen by default if a default proxy server is specified
- if (gArgs.SoftSetBoolArg("-listen", false))
+ if (args.SoftSetBoolArg("-listen", false))
LogPrintf("%s: parameter interaction: -proxy set -> setting -listen=0\n", __func__);
// to protect privacy, do not use UPNP when a proxy is set. The user may still specify -listen=1
// to listen locally, so don't rely on this happening through -listen below.
- if (gArgs.SoftSetBoolArg("-upnp", false))
+ if (args.SoftSetBoolArg("-upnp", false))
LogPrintf("%s: parameter interaction: -proxy set -> setting -upnp=0\n", __func__);
// to protect privacy, do not discover addresses by default
- if (gArgs.SoftSetBoolArg("-discover", false))
+ if (args.SoftSetBoolArg("-discover", false))
LogPrintf("%s: parameter interaction: -proxy set -> setting -discover=0\n", __func__);
}
- if (!gArgs.GetBoolArg("-listen", DEFAULT_LISTEN)) {
+ if (!args.GetBoolArg("-listen", DEFAULT_LISTEN)) {
// do not map ports or try to retrieve public IP when not listening (pointless)
- if (gArgs.SoftSetBoolArg("-upnp", false))
+ if (args.SoftSetBoolArg("-upnp", false))
LogPrintf("%s: parameter interaction: -listen=0 -> setting -upnp=0\n", __func__);
- if (gArgs.SoftSetBoolArg("-discover", false))
+ if (args.SoftSetBoolArg("-discover", false))
LogPrintf("%s: parameter interaction: -listen=0 -> setting -discover=0\n", __func__);
- if (gArgs.SoftSetBoolArg("-listenonion", false))
+ if (args.SoftSetBoolArg("-listenonion", false))
LogPrintf("%s: parameter interaction: -listen=0 -> setting -listenonion=0\n", __func__);
}
- if (gArgs.IsArgSet("-externalip")) {
+ if (args.IsArgSet("-externalip")) {
// if an explicit public IP is specified, do not try to find others
- if (gArgs.SoftSetBoolArg("-discover", false))
+ if (args.SoftSetBoolArg("-discover", false))
LogPrintf("%s: parameter interaction: -externalip set -> setting -discover=0\n", __func__);
}
// disable whitelistrelay in blocksonly mode
- if (gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)) {
- if (gArgs.SoftSetBoolArg("-whitelistrelay", false))
+ if (args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)) {
+ if (args.SoftSetBoolArg("-whitelistrelay", false))
LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -whitelistrelay=0\n", __func__);
}
// Forcing relay from whitelisted hosts implies we will accept relays from them in the first place.
- if (gArgs.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) {
- if (gArgs.SoftSetBoolArg("-whitelistrelay", true))
+ if (args.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) {
+ if (args.SoftSetBoolArg("-whitelistrelay", true))
LogPrintf("%s: parameter interaction: -whitelistforcerelay=1 -> setting -whitelistrelay=1\n", __func__);
}
}
@@ -863,18 +850,18 @@ void InitParameterInteraction()
* 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()
+void InitLogging(const ArgsManager& args)
{
- LogInstance().m_print_to_file = !gArgs.IsArgNegated("-debuglogfile");
- LogInstance().m_file_path = AbsPathForConfigVal(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE));
- LogInstance().m_print_to_console = gArgs.GetBoolArg("-printtoconsole", !gArgs.GetBoolArg("-daemon", false));
- LogInstance().m_log_timestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS);
- LogInstance().m_log_time_micros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS);
+ LogInstance().m_print_to_file = !args.IsArgNegated("-debuglogfile");
+ LogInstance().m_file_path = AbsPathForConfigVal(args.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE));
+ LogInstance().m_print_to_console = args.GetBoolArg("-printtoconsole", !args.GetBoolArg("-daemon", false));
+ LogInstance().m_log_timestamps = args.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS);
+ LogInstance().m_log_time_micros = args.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS);
#ifdef HAVE_THREAD_LOCAL
- LogInstance().m_log_threadnames = gArgs.GetBoolArg("-logthreadnames", DEFAULT_LOGTHREADNAMES);
+ LogInstance().m_log_threadnames = args.GetBoolArg("-logthreadnames", DEFAULT_LOGTHREADNAMES);
#endif
- fLogIPs = gArgs.GetBoolArg("-logips", DEFAULT_LOGIPS);
+ fLogIPs = args.GetBoolArg("-logips", DEFAULT_LOGIPS);
std::string version_string = FormatFullVersion();
#ifdef DEBUG
@@ -909,7 +896,7 @@ std::set<BlockFilterType> g_enabled_filter_types;
std::terminate();
};
-bool AppInitBasicSetup()
+bool AppInitBasicSetup(ArgsManager& args)
{
// ********************************************************* Step 1: setup
#ifdef _MSC_VER
@@ -929,7 +916,7 @@ bool AppInitBasicSetup()
}
#ifndef WIN32
- if (!gArgs.GetBoolArg("-sysperms", false)) {
+ if (!args.GetBoolArg("-sysperms", false)) {
umask(077);
}
@@ -951,7 +938,7 @@ bool AppInitBasicSetup()
return true;
}
-bool AppInitParameterInteraction()
+bool AppInitParameterInteraction(const ArgsManager& args)
{
const CChainParams& chainparams = Params();
// ********************************************************* Step 2: parameter interactions
@@ -961,9 +948,9 @@ bool AppInitParameterInteraction()
// Error 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.
- std::string network = gArgs.GetChainName();
+ std::string network = args.GetChainName();
bilingual_str errors;
- for (const auto& arg : gArgs.GetUnsuitableSectionOnlyArgs()) {
+ for (const auto& arg : args.GetUnsuitableSectionOnlyArgs()) {
errors += strprintf(_("Config setting for %s only applied on %s network when in [%s] section.") + Untranslated("\n"), arg, network, network);
}
@@ -973,7 +960,7 @@ bool AppInitParameterInteraction()
// Warn if unrecognized section name are present in the config file.
bilingual_str warnings;
- for (const auto& section : gArgs.GetUnrecognizedSections()) {
+ for (const auto& section : args.GetUnrecognizedSections()) {
warnings += strprintf(Untranslated("%s:%i ") + _("Section [%s] is not recognized.") + Untranslated("\n"), section.m_file, section.m_line, section.m_name);
}
@@ -982,15 +969,15 @@ bool AppInitParameterInteraction()
}
if (!fs::is_directory(GetBlocksDir())) {
- return InitError(strprintf(_("Specified blocks directory \"%s\" does not exist."), gArgs.GetArg("-blocksdir", "")));
+ return InitError(strprintf(_("Specified blocks directory \"%s\" does not exist."), args.GetArg("-blocksdir", "")));
}
// parse and validate enabled filter types
- std::string blockfilterindex_value = gArgs.GetArg("-blockfilterindex", DEFAULT_BLOCKFILTERINDEX);
+ std::string blockfilterindex_value = args.GetArg("-blockfilterindex", DEFAULT_BLOCKFILTERINDEX);
if (blockfilterindex_value == "" || blockfilterindex_value == "1") {
g_enabled_filter_types = AllBlockFilterTypes();
} else if (blockfilterindex_value != "0") {
- const std::vector<std::string> names = gArgs.GetArgs("-blockfilterindex");
+ const std::vector<std::string> names = args.GetArgs("-blockfilterindex");
for (const auto& name : names) {
BlockFilterType filter_type;
if (!BlockFilterTypeByName(name, filter_type)) {
@@ -1001,7 +988,7 @@ bool AppInitParameterInteraction()
}
// Signal NODE_COMPACT_FILTERS if peerblockfilters and basic filters index are both enabled.
- if (gArgs.GetBoolArg("-peerblockfilters", DEFAULT_PEERBLOCKFILTERS)) {
+ if (args.GetBoolArg("-peerblockfilters", DEFAULT_PEERBLOCKFILTERS)) {
if (g_enabled_filter_types.count(BlockFilterType::BASIC) != 1) {
return InitError(_("Cannot set -peerblockfilters without -blockfilterindex."));
}
@@ -1010,8 +997,8 @@ bool AppInitParameterInteraction()
}
// if using block pruning, then disallow txindex
- if (gArgs.GetArg("-prune", 0)) {
- if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX))
+ if (args.GetArg("-prune", 0)) {
+ if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX))
return InitError(_("Prune mode is incompatible with -txindex."));
if (!g_enabled_filter_types.empty()) {
return InitError(_("Prune mode is incompatible with -blockfilterindex."));
@@ -1019,14 +1006,14 @@ bool AppInitParameterInteraction()
}
// -bind and -whitebind can't be set when not listening
- size_t nUserBind = gArgs.GetArgs("-bind").size() + gArgs.GetArgs("-whitebind").size();
- if (nUserBind != 0 && !gArgs.GetBoolArg("-listen", DEFAULT_LISTEN)) {
+ size_t nUserBind = args.GetArgs("-bind").size() + args.GetArgs("-whitebind").size();
+ if (nUserBind != 0 && !args.GetBoolArg("-listen", DEFAULT_LISTEN)) {
return InitError(Untranslated("Cannot set -bind or -whitebind together with -listen=0"));
}
// Make sure enough file descriptors are available
int nBind = std::max(nUserBind, size_t(1));
- nUserMaxConnections = gArgs.GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
+ nUserMaxConnections = args.GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
nMaxConnections = std::max(nUserMaxConnections, 0);
// Trim requested connection counts, to fit into system limitations
@@ -1046,9 +1033,9 @@ bool AppInitParameterInteraction()
InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations."), nUserMaxConnections, nMaxConnections));
// ********************************************************* Step 3: parameter-to-internal-flags
- if (gArgs.IsArgSet("-debug")) {
+ if (args.IsArgSet("-debug")) {
// Special-case: if -debug=0/-nodebug is set, turn off debugging messages
- const std::vector<std::string> categories = gArgs.GetArgs("-debug");
+ const std::vector<std::string> categories = args.GetArgs("-debug");
if (std::none_of(categories.begin(), categories.end(),
[](std::string cat){return cat == "0" || cat == "none";})) {
@@ -1061,28 +1048,28 @@ bool AppInitParameterInteraction()
}
// Now remove the logging categories which were explicitly excluded
- for (const std::string& cat : gArgs.GetArgs("-debugexclude")) {
+ for (const std::string& cat : args.GetArgs("-debugexclude")) {
if (!LogInstance().DisableCategory(cat)) {
InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debugexclude", cat));
}
}
// Checkmempool and checkblockindex default to true in regtest mode
- int ratio = std::min<int>(std::max<int>(gArgs.GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);
+ int ratio = std::min<int>(std::max<int>(args.GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);
if (ratio != 0) {
mempool.setSanityCheck(1.0 / ratio);
}
- fCheckBlockIndex = gArgs.GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks());
- fCheckpointsEnabled = gArgs.GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED);
+ fCheckBlockIndex = args.GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks());
+ fCheckpointsEnabled = args.GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED);
- hashAssumeValid = uint256S(gArgs.GetArg("-assumevalid", chainparams.GetConsensus().defaultAssumeValid.GetHex()));
+ hashAssumeValid = uint256S(args.GetArg("-assumevalid", chainparams.GetConsensus().defaultAssumeValid.GetHex()));
if (!hashAssumeValid.IsNull())
LogPrintf("Assuming ancestors of block %s have valid signatures.\n", hashAssumeValid.GetHex());
else
LogPrintf("Validating signatures for all blocks.\n");
- if (gArgs.IsArgSet("-minimumchainwork")) {
- const std::string minChainWorkStr = gArgs.GetArg("-minimumchainwork", "");
+ if (args.IsArgSet("-minimumchainwork")) {
+ const std::string minChainWorkStr = args.GetArg("-minimumchainwork", "");
if (!IsHexNumber(minChainWorkStr)) {
return InitError(strprintf(Untranslated("Invalid non-hex (%s) minimum chain work value specified"), minChainWorkStr));
}
@@ -1096,22 +1083,21 @@ bool AppInitParameterInteraction()
}
// mempool limits
- int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
- int64_t nMempoolSizeMin = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40;
+ int64_t nMempoolSizeMax = args.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
+ int64_t nMempoolSizeMin = args.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40;
if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin)
return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(nMempoolSizeMin / 1000000.0)));
// incremental relay fee sets the minimum feerate increase necessary for BIP 125 replacement in the mempool
// and the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting.
- if (gArgs.IsArgSet("-incrementalrelayfee"))
- {
+ if (args.IsArgSet("-incrementalrelayfee")) {
CAmount n = 0;
- if (!ParseMoney(gArgs.GetArg("-incrementalrelayfee", ""), n))
- return InitError(AmountErrMsg("incrementalrelayfee", gArgs.GetArg("-incrementalrelayfee", "")));
+ if (!ParseMoney(args.GetArg("-incrementalrelayfee", ""), n))
+ return InitError(AmountErrMsg("incrementalrelayfee", args.GetArg("-incrementalrelayfee", "")));
incrementalRelayFee = CFeeRate(n);
}
// block pruning; get the amount of disk space (in MiB) to allot for block & undo files
- int64_t nPruneArg = gArgs.GetArg("-prune", 0);
+ int64_t nPruneArg = args.GetArg("-prune", 0);
if (nPruneArg < 0) {
return InitError(_("Prune cannot be configured with a negative value."));
}
@@ -1128,20 +1114,20 @@ bool AppInitParameterInteraction()
fPruneMode = true;
}
- nConnectTimeout = gArgs.GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
+ nConnectTimeout = args.GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
if (nConnectTimeout <= 0) {
nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
}
- peer_connect_timeout = gArgs.GetArg("-peertimeout", DEFAULT_PEER_CONNECT_TIMEOUT);
+ peer_connect_timeout = args.GetArg("-peertimeout", DEFAULT_PEER_CONNECT_TIMEOUT);
if (peer_connect_timeout <= 0) {
return InitError(Untranslated("peertimeout cannot be configured with a negative value."));
}
- if (gArgs.IsArgSet("-minrelaytxfee")) {
+ if (args.IsArgSet("-minrelaytxfee")) {
CAmount n = 0;
- if (!ParseMoney(gArgs.GetArg("-minrelaytxfee", ""), n)) {
- return InitError(AmountErrMsg("minrelaytxfee", gArgs.GetArg("-minrelaytxfee", "")));
+ if (!ParseMoney(args.GetArg("-minrelaytxfee", ""), n)) {
+ return InitError(AmountErrMsg("minrelaytxfee", args.GetArg("-minrelaytxfee", "")));
}
// High fee check is done afterward in CWallet::CreateWalletFromFile()
::minRelayTxFee = CFeeRate(n);
@@ -1153,48 +1139,46 @@ bool AppInitParameterInteraction()
// Sanity check argument for min fee for including tx in block
// TODO: Harmonize which arguments need sanity checking and where that happens
- if (gArgs.IsArgSet("-blockmintxfee"))
- {
+ if (args.IsArgSet("-blockmintxfee")) {
CAmount n = 0;
- if (!ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n))
- return InitError(AmountErrMsg("blockmintxfee", gArgs.GetArg("-blockmintxfee", "")));
+ if (!ParseMoney(args.GetArg("-blockmintxfee", ""), n))
+ return InitError(AmountErrMsg("blockmintxfee", args.GetArg("-blockmintxfee", "")));
}
// Feerate used to define dust. Shouldn't be changed lightly as old
// implementations may inadvertently create non-standard transactions
- if (gArgs.IsArgSet("-dustrelayfee"))
- {
+ if (args.IsArgSet("-dustrelayfee")) {
CAmount n = 0;
- if (!ParseMoney(gArgs.GetArg("-dustrelayfee", ""), n))
- return InitError(AmountErrMsg("dustrelayfee", gArgs.GetArg("-dustrelayfee", "")));
+ if (!ParseMoney(args.GetArg("-dustrelayfee", ""), n))
+ return InitError(AmountErrMsg("dustrelayfee", args.GetArg("-dustrelayfee", "")));
dustRelayFee = CFeeRate(n);
}
- fRequireStandard = !gArgs.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());
+ fRequireStandard = !args.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());
if (!chainparams.IsTestChain() && !fRequireStandard) {
return InitError(strprintf(Untranslated("acceptnonstdtxn is not currently supported for %s chain"), chainparams.NetworkIDString()));
}
- nBytesPerSigOp = gArgs.GetArg("-bytespersigop", nBytesPerSigOp);
+ nBytesPerSigOp = args.GetArg("-bytespersigop", nBytesPerSigOp);
if (!g_wallet_init_interface.ParameterInteraction()) return false;
- fIsBareMultisigStd = gArgs.GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG);
- fAcceptDatacarrier = gArgs.GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER);
- nMaxDatacarrierBytes = gArgs.GetArg("-datacarriersize", nMaxDatacarrierBytes);
+ fIsBareMultisigStd = args.GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG);
+ fAcceptDatacarrier = args.GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER);
+ nMaxDatacarrierBytes = args.GetArg("-datacarriersize", nMaxDatacarrierBytes);
// Option to startup with mocktime set (used for regression testing):
- SetMockTime(gArgs.GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op
+ SetMockTime(args.GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op
- if (gArgs.GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS))
+ if (args.GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS))
nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM);
- if (gArgs.GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) < 0)
+ if (args.GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) < 0)
return InitError(Untranslated("rpcserialversion must be non-negative."));
- if (gArgs.GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) > 1)
+ if (args.GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) > 1)
return InitError(Untranslated("Unknown rpcserialversion requested."));
- nMaxTipAge = gArgs.GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE);
+ nMaxTipAge = args.GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE);
return true;
}
@@ -1247,14 +1231,15 @@ bool AppInitLockDataDirectory()
bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
{
+ const ArgsManager& args = *Assert(node.args);
const CChainParams& chainparams = Params();
// ********************************************************* Step 4a: application initialization
- if (!CreatePidFile()) {
+ if (!CreatePidFile(args)) {
// Detailed error printed inside CreatePidFile().
return false;
}
if (LogInstance().m_print_to_file) {
- if (gArgs.GetBoolArg("-shrinkdebugfile", LogInstance().DefaultShrinkDebugFile())) {
+ if (args.GetBoolArg("-shrinkdebugfile", LogInstance().DefaultShrinkDebugFile())) {
// 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
LogInstance().ShrinkDebugFile();
@@ -1271,10 +1256,10 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
LogPrintf("Using data directory %s\n", GetDataDir().string());
// Only log conf file usage message if conf file actually exists.
- fs::path config_file_path = GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME));
+ fs::path config_file_path = GetConfigFile(args.GetArg("-conf", BITCOIN_CONF_FILENAME));
if (fs::exists(config_file_path)) {
LogPrintf("Config file: %s\n", config_file_path.string());
- } else if (gArgs.IsArgSet("-conf")) {
+ } else if (args.IsArgSet("-conf")) {
// Warn if no conf file exists at path provided by user
InitWarning(strprintf(_("The specified config file %s does not exist\n"), config_file_path.string()));
} else {
@@ -1283,23 +1268,23 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
}
// Log the config arguments to debug.log
- gArgs.LogArgs();
+ args.LogArgs();
LogPrintf("Using at most %i automatic connections (%i file descriptors available)\n", nMaxConnections, nFD);
// Warn about relative -datadir path.
- if (gArgs.IsArgSet("-datadir") && !fs::path(gArgs.GetArg("-datadir", "")).is_absolute()) {
+ if (args.IsArgSet("-datadir") && !fs::path(args.GetArg("-datadir", "")).is_absolute()) {
LogPrintf("Warning: relative datadir option '%s' specified, which will be interpreted relative to the " /* Continued */
"current working directory '%s'. This is fragile, because if bitcoin is started in the future "
"from a different location, it will be unable to locate the current data files. There could "
"also be data loss if bitcoin is started while in a temporary directory.\n",
- gArgs.GetArg("-datadir", ""), fs::current_path().string());
+ args.GetArg("-datadir", ""), fs::current_path().string());
}
InitSignatureCache();
InitScriptExecutionCache();
- int script_threads = gArgs.GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS);
+ int script_threads = args.GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS);
if (script_threads <= 0) {
// -par=0 means autodetect (number of cores - 1 script threads)
// -par=-n means "leave n cores free" (number of cores - n - 1 script threads)
@@ -1355,8 +1340,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
* that the server is there and will be ready later). Warmup mode will
* be disabled when initialisation is finished.
*/
- if (gArgs.GetBoolArg("-server", false))
- {
+ if (args.GetBoolArg("-server", false)) {
uiInterface.InitMessage_connect(SetRPCWarmupStatus);
if (!AppInitServers(context, node))
return InitError(_("Unable to start HTTP server. See debug log for details."));
@@ -1376,9 +1360,9 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
// need to reindex later.
assert(!node.banman);
- node.banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", &uiInterface, gArgs.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME));
+ node.banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", &uiInterface, args.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME));
assert(!node.connman);
- node.connman = MakeUnique<CConnman>(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max()), gArgs.GetBoolArg("-networkactive", true));
+ node.connman = MakeUnique<CConnman>(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max()), args.GetBoolArg("-networkactive", true));
// Make mempool generally available in the node context. For example the connection manager, wallet, or RPC threads,
// which are all started after this, may use it from the node context.
assert(!node.mempool);
@@ -1387,12 +1371,12 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
node.chainman = &g_chainman;
ChainstateManager& chainman = *Assert(node.chainman);
- node.peer_logic.reset(new PeerLogicValidation(node.connman.get(), node.banman.get(), *node.scheduler, chainman, *node.mempool));
+ node.peer_logic.reset(new PeerLogicValidation(*node.connman, node.banman.get(), *node.scheduler, chainman, *node.mempool));
RegisterValidationInterface(node.peer_logic.get());
// sanitize comments per BIP-0014, format user agent and check total size
std::vector<std::string> uacomments;
- for (const std::string& cmt : gArgs.GetArgs("-uacomment")) {
+ for (const std::string& cmt : args.GetArgs("-uacomment")) {
if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT))
return InitError(strprintf(_("User Agent comment (%s) contains unsafe characters."), cmt));
uacomments.push_back(cmt);
@@ -1403,9 +1387,9 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
strSubVersion.size(), MAX_SUBVERSION_LENGTH));
}
- if (gArgs.IsArgSet("-onlynet")) {
+ if (args.IsArgSet("-onlynet")) {
std::set<enum Network> nets;
- for (const std::string& snet : gArgs.GetArgs("-onlynet")) {
+ for (const std::string& snet : args.GetArgs("-onlynet")) {
enum Network net = ParseNetwork(snet);
if (net == NET_UNROUTABLE)
return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet));
@@ -1419,12 +1403,12 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
}
// Check for host lookup allowed before parsing any network related parameters
- fNameLookup = gArgs.GetBoolArg("-dns", DEFAULT_NAME_LOOKUP);
+ fNameLookup = args.GetBoolArg("-dns", DEFAULT_NAME_LOOKUP);
- bool proxyRandomize = gArgs.GetBoolArg("-proxyrandomize", DEFAULT_PROXYRANDOMIZE);
+ bool proxyRandomize = args.GetBoolArg("-proxyrandomize", DEFAULT_PROXYRANDOMIZE);
// -proxy sets a proxy for all outgoing network traffic
// -noproxy (or -proxy=0) as well as the empty string can be used to not set a proxy, this is the default
- std::string proxyArg = gArgs.GetArg("-proxy", "");
+ std::string proxyArg = args.GetArg("-proxy", "");
SetReachable(NET_ONION, false);
if (proxyArg != "" && proxyArg != "0") {
CService proxyAddr;
@@ -1446,7 +1430,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
// -onion can be used to set only a proxy for .onion, or override normal proxy for .onion addresses
// -noonion (or -onion=0) disables connecting to .onion entirely
// An empty string is used to not override the onion proxy (in which case it defaults to -proxy set above, or none)
- std::string onionArg = gArgs.GetArg("-onion", "");
+ std::string onionArg = args.GetArg("-onion", "");
if (onionArg != "") {
if (onionArg == "0") { // Handle -noonion/-onion=0
SetReachable(NET_ONION, false);
@@ -1464,11 +1448,11 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
}
// see Step 2: parameter interactions for more information about these
- fListen = gArgs.GetBoolArg("-listen", DEFAULT_LISTEN);
- fDiscover = gArgs.GetBoolArg("-discover", true);
- g_relay_txes = !gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
+ fListen = args.GetBoolArg("-listen", DEFAULT_LISTEN);
+ fDiscover = args.GetBoolArg("-discover", true);
+ g_relay_txes = !args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
- for (const std::string& strAddr : gArgs.GetArgs("-externalip")) {
+ for (const std::string& strAddr : args.GetArgs("-externalip")) {
CService addrLocal;
if (Lookup(strAddr, addrLocal, GetListenPort(), fNameLookup) && addrLocal.IsValid())
AddLocal(addrLocal, LOCAL_MANUAL);
@@ -1477,8 +1461,8 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
}
// Read asmap file if configured
- if (gArgs.IsArgSet("-asmap")) {
- fs::path asmap_path = fs::path(gArgs.GetArg("-asmap", ""));
+ if (args.IsArgSet("-asmap")) {
+ fs::path asmap_path = fs::path(args.GetArg("-asmap", ""));
if (asmap_path.empty()) {
asmap_path = DEFAULT_ASMAP_FILENAME;
}
@@ -1511,22 +1495,22 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
uint64_t nMaxOutboundLimit = 0; //unlimited unless -maxuploadtarget is set
uint64_t nMaxOutboundTimeframe = MAX_UPLOAD_TIMEFRAME;
- if (gArgs.IsArgSet("-maxuploadtarget")) {
- nMaxOutboundLimit = gArgs.GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024;
+ if (args.IsArgSet("-maxuploadtarget")) {
+ nMaxOutboundLimit = args.GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET) * 1024 * 1024;
}
// ********************************************************* Step 7: load block chain
- fReindex = gArgs.GetBoolArg("-reindex", false);
- bool fReindexChainState = gArgs.GetBoolArg("-reindex-chainstate", false);
+ fReindex = args.GetBoolArg("-reindex", false);
+ bool fReindexChainState = args.GetBoolArg("-reindex-chainstate", false);
// cache size calculations
- int64_t nTotalCache = (gArgs.GetArg("-dbcache", nDefaultDbCache) << 20);
+ int64_t nTotalCache = (args.GetArg("-dbcache", nDefaultDbCache) << 20);
nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache
nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greater than nMaxDbcache
int64_t nBlockTreeDBCache = std::min(nTotalCache / 8, nMaxBlockDBCache << 20);
nTotalCache -= nBlockTreeDBCache;
- int64_t nTxIndexCache = std::min(nTotalCache / 8, gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX) ? nMaxTxIndexCache << 20 : 0);
+ int64_t nTxIndexCache = std::min(nTotalCache / 8, args.GetBoolArg("-txindex", DEFAULT_TXINDEX) ? nMaxTxIndexCache << 20 : 0);
nTotalCache -= nTxIndexCache;
int64_t filter_index_cache = 0;
if (!g_enabled_filter_types.empty()) {
@@ -1539,10 +1523,10 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
nCoinDBCache = std::min(nCoinDBCache, nMaxCoinsDBCache << 20); // cap total coins db cache
nTotalCache -= nCoinDBCache;
int64_t nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache
- int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
+ int64_t nMempoolSizeMax = args.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
LogPrintf("Cache configuration:\n");
LogPrintf("* Using %.1f MiB for block index database\n", nBlockTreeDBCache * (1.0 / 1024 / 1024));
- if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
+ if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
LogPrintf("* Using %.1f MiB for transaction index database\n", nTxIndexCache * (1.0 / 1024 / 1024));
}
for (BlockFilterType filter_type : g_enabled_filter_types) {
@@ -1707,7 +1691,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
for (CChainState* chainstate : chainman.GetAll()) {
if (!is_coinsview_empty(chainstate)) {
uiInterface.InitMessage(_("Verifying blocks...").translated);
- if (fHavePruned && gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) {
+ if (fHavePruned && args.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) {
LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks\n",
MIN_BLOCKS_TO_KEEP);
}
@@ -1725,10 +1709,10 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
// Only verify the DB of the active chainstate. This is fixed in later
// work when we allow VerifyDB to be parameterized by chainstate.
if (&::ChainstateActive() == chainstate &&
- !CVerifyDB().VerifyDB(
+ !CVerifyDB().VerifyDB(
chainparams, &chainstate->CoinsDB(),
- gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
- gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) {
+ args.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
+ args.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) {
strLoadError = _("Corrupted block database detected");
failed_verification = true;
break;
@@ -1784,7 +1768,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
fFeeEstimatesInitialized = true;
// ********************************************************* Step 8: start indexers
- if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
+ if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
g_txindex = MakeUnique<TxIndex>(nTxIndexCache, false, fReindex);
g_txindex->Start();
}
@@ -1844,16 +1828,31 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
}
#if HAVE_SYSTEM
- if (gArgs.IsArgSet("-blocknotify"))
+ if (args.IsArgSet("-blocknotify")) {
+ const std::string block_notify = args.GetArg("-blocknotify", "");
+ const auto BlockNotifyCallback = [block_notify](SynchronizationState sync_state, const CBlockIndex* pBlockIndex) {
+ if (sync_state != SynchronizationState::POST_INIT || !pBlockIndex)
+ return;
+
+ std::string strCmd = block_notify;
+ if (!strCmd.empty()) {
+ boost::replace_all(strCmd, "%s", pBlockIndex->GetBlockHash().GetHex());
+ std::thread t(runCommand, strCmd);
+ t.detach(); // thread runs free
+ }
+ };
uiInterface.NotifyBlockTip_connect(BlockNotifyCallback);
+ }
#endif
std::vector<fs::path> vImportFiles;
- for (const std::string& strFile : gArgs.GetArgs("-loadblock")) {
+ for (const std::string& strFile : args.GetArgs("-loadblock")) {
vImportFiles.push_back(strFile);
}
- g_load_block = std::thread(&TraceThread<std::function<void()>>, "loadblk", [=, &chainman]{ ThreadImport(chainman, vImportFiles); });
+ g_load_block = std::thread(&TraceThread<std::function<void()>>, "loadblk", [=, &chainman, &args] {
+ ThreadImport(chainman, vImportFiles, args);
+ });
// Wait for genesis block to be processed
{
@@ -1892,13 +1891,13 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
}
LogPrintf("nBestHeight = %d\n", chain_active_height);
- if (gArgs.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
+ if (args.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
StartTorControl();
Discover();
// Map ports with UPnP
- if (gArgs.GetBoolArg("-upnp", DEFAULT_UPNP)) {
+ if (args.GetBoolArg("-upnp", DEFAULT_UPNP)) {
StartMapPort();
}
@@ -1913,41 +1912,41 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
connOptions.uiInterface = &uiInterface;
connOptions.m_banman = node.banman.get();
connOptions.m_msgproc = node.peer_logic.get();
- connOptions.nSendBufferMaxSize = 1000*gArgs.GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER);
- connOptions.nReceiveFloodSize = 1000*gArgs.GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER);
- connOptions.m_added_nodes = gArgs.GetArgs("-addnode");
+ connOptions.nSendBufferMaxSize = 1000 * args.GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER);
+ connOptions.nReceiveFloodSize = 1000 * args.GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER);
+ connOptions.m_added_nodes = args.GetArgs("-addnode");
connOptions.nMaxOutboundTimeframe = nMaxOutboundTimeframe;
connOptions.nMaxOutboundLimit = nMaxOutboundLimit;
connOptions.m_peer_connect_timeout = peer_connect_timeout;
- for (const std::string& strBind : gArgs.GetArgs("-bind")) {
+ for (const std::string& strBind : args.GetArgs("-bind")) {
CService addrBind;
if (!Lookup(strBind, addrBind, GetListenPort(), false)) {
return InitError(ResolveErrMsg("bind", strBind));
}
connOptions.vBinds.push_back(addrBind);
}
- for (const std::string& strBind : gArgs.GetArgs("-whitebind")) {
+ for (const std::string& strBind : args.GetArgs("-whitebind")) {
NetWhitebindPermissions whitebind;
bilingual_str error;
if (!NetWhitebindPermissions::TryParse(strBind, whitebind, error)) return InitError(error);
connOptions.vWhiteBinds.push_back(whitebind);
}
- for (const auto& net : gArgs.GetArgs("-whitelist")) {
+ for (const auto& net : args.GetArgs("-whitelist")) {
NetWhitelistPermissions subnet;
bilingual_str error;
if (!NetWhitelistPermissions::TryParse(net, subnet, error)) return InitError(error);
connOptions.vWhitelistedRange.push_back(subnet);
}
- connOptions.vSeedNodes = gArgs.GetArgs("-seednode");
+ connOptions.vSeedNodes = args.GetArgs("-seednode");
// Initiate outbound connections unless connect=0
- connOptions.m_use_addrman_outgoing = !gArgs.IsArgSet("-connect");
+ connOptions.m_use_addrman_outgoing = !args.IsArgSet("-connect");
if (!connOptions.m_use_addrman_outgoing) {
- const auto connect = gArgs.GetArgs("-connect");
+ const auto connect = args.GetArgs("-connect");
if (connect.size() != 1 || connect[0] != "0") {
connOptions.m_specified_outgoing = connect;
}
diff --git a/src/init.h b/src/init.h
index 20008ba5be..ce12a80dc7 100644
--- a/src/init.h
+++ b/src/init.h
@@ -8,8 +8,8 @@
#include <memory>
#include <string>
-#include <util/system.h>
+class ArgsManager;
struct NodeContext;
namespace interfaces {
struct BlockAndHeaderTipInfo;
@@ -25,21 +25,21 @@ class Ref;
void Interrupt(NodeContext& node);
void Shutdown(NodeContext& node);
//!Initialize the logging infrastructure
-void InitLogging();
+void InitLogging(const ArgsManager& args);
//!Parameter interaction: change current parameters depending on various rules
-void InitParameterInteraction();
+void InitParameterInteraction(ArgsManager& args);
/** Initialize bitcoin core: Basic context setup.
* @note This can be done before daemonization. Do not call Shutdown() if this function fails.
* @pre Parameters should be parsed and config file should be read.
*/
-bool AppInitBasicSetup();
+bool AppInitBasicSetup(ArgsManager& args);
/**
* Initialization: parameter interaction.
* @note This can be done before daemonization. Do not call Shutdown() if this function fails.
* @pre Parameters should be parsed and config file should be read, AppInitBasicSetup should have been called.
*/
-bool AppInitParameterInteraction();
+bool AppInitParameterInteraction(const ArgsManager& args);
/**
* Initialization sanity checks: ecc init, sanity checks, dir lock.
* @note This can be done before daemonization. Do not call Shutdown() if this function fails.
diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp
index 21400d00f8..206262eb03 100644
--- a/src/interfaces/node.cpp
+++ b/src/interfaces/node.cpp
@@ -57,27 +57,13 @@ class NodeImpl : public Node
{
public:
NodeImpl(NodeContext* context) { setContext(context); }
- void initError(const bilingual_str& message) override { InitError(message); }
- bool parseParameters(int argc, const char* const argv[], std::string& error) override
- {
- return gArgs.ParseParameters(argc, argv, error);
- }
- bool readConfigFiles(std::string& error) override { return gArgs.ReadConfigFiles(error, true); }
- void forceSetArg(const std::string& arg, const std::string& value) override { gArgs.ForceSetArg(arg, value); }
- bool softSetArg(const std::string& arg, const std::string& value) override { return gArgs.SoftSetArg(arg, value); }
- bool softSetBoolArg(const std::string& arg, bool value) override { return gArgs.SoftSetBoolArg(arg, value); }
- void selectParams(const std::string& network) override { SelectParams(network); }
- bool initSettings(std::string& error) override { return gArgs.InitSettings(error); }
- uint64_t getAssumedBlockchainSize() override { return Params().AssumedBlockchainSize(); }
- uint64_t getAssumedChainStateSize() override { return Params().AssumedChainStateSize(); }
- std::string getNetwork() override { return Params().NetworkIDString(); }
- void initLogging() override { InitLogging(); }
- void initParameterInteraction() override { InitParameterInteraction(); }
+ void initLogging() override { InitLogging(*Assert(m_context->args)); }
+ void initParameterInteraction() override { InitParameterInteraction(*Assert(m_context->args)); }
bilingual_str getWarnings() override { return GetWarnings(true); }
uint32_t getLogCategories() override { return LogInstance().GetCategoryMask(); }
bool baseInitialize() override
{
- return AppInitBasicSetup() && AppInitParameterInteraction() && AppInitSanityChecks() &&
+ return AppInitBasicSetup(gArgs) && AppInitParameterInteraction(gArgs) && AppInitSanityChecks() &&
AppInitLockDataDirectory();
}
bool appInitMain(interfaces::BlockAndHeaderTipInfo* tip_info) override
@@ -109,7 +95,6 @@ public:
StopMapPort();
}
}
- void setupServerArgs() override { return SetupServerArgs(*m_context); }
bool getProxy(Network net, proxyType& proxy_info) override { return GetProxy(net, proxy_info); }
size_t getNodeCount(CConnman::NumConnections flags) override
{
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index 753f3e6b13..0cff7ae3a1 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -55,41 +55,6 @@ class Node
public:
virtual ~Node() {}
- //! Send init error.
- virtual void initError(const bilingual_str& message) = 0;
-
- //! Set command line arguments.
- virtual bool parseParameters(int argc, const char* const argv[], std::string& error) = 0;
-
- //! Set a command line argument
- virtual void forceSetArg(const std::string& arg, const std::string& value) = 0;
-
- //! Set a command line argument if it doesn't already have a value
- virtual bool softSetArg(const std::string& arg, const std::string& value) = 0;
-
- //! Set a command line boolean argument if it doesn't already have a value
- virtual bool softSetBoolArg(const std::string& arg, bool value) = 0;
-
- //! Load settings from configuration file.
- virtual bool readConfigFiles(std::string& error) = 0;
-
- //! Choose network parameters.
- virtual void selectParams(const std::string& network) = 0;
-
- //! Read and update <datadir>/settings.json file with saved settings. This
- //! needs to be called after selectParams() because the settings file
- //! location is network-specific.
- virtual bool initSettings(std::string& error) = 0;
-
- //! Get the (assumed) blockchain size.
- virtual uint64_t getAssumedBlockchainSize() = 0;
-
- //! Get the (assumed) chain state size.
- virtual uint64_t getAssumedChainStateSize() = 0;
-
- //! Get network name.
- virtual std::string getNetwork() = 0;
-
//! Init logging.
virtual void initLogging() = 0;
@@ -117,9 +82,6 @@ public:
//! Return whether shutdown was requested.
virtual bool shutdownRequested() = 0;
- //! Setup arguments
- virtual void setupServerArgs() = 0;
-
//! Map port.
virtual void mapPort(bool use_upnp) = 0;
diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp
index 7fd24425cf..937e602fb0 100644
--- a/src/interfaces/wallet.cpp
+++ b/src/interfaces/wallet.cpp
@@ -37,6 +37,7 @@ namespace {
//! Construct wallet tx struct.
WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
{
+ LOCK(wallet.cs_wallet);
WalletTx result;
result.tx = wtx.tx;
result.txin_is_mine.reserve(wtx.tx->vin.size());
@@ -132,7 +133,11 @@ public:
{
return m_wallet->SignMessage(message, pkhash, str_sig);
}
- bool isSpendable(const CTxDestination& dest) override { return m_wallet->IsMine(dest) & ISMINE_SPENDABLE; }
+ bool isSpendable(const CTxDestination& dest) override
+ {
+ LOCK(m_wallet->cs_wallet);
+ return m_wallet->IsMine(dest) & ISMINE_SPENDABLE;
+ }
bool haveWatchOnly() override
{
auto spk_man = m_wallet->GetLegacyScriptPubKeyMan();
diff --git a/src/net.cpp b/src/net.cpp
index 6c1980735c..883e57bdf0 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -530,6 +530,8 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap)
}
X(nLastSend);
X(nLastRecv);
+ X(nLastTXTime);
+ X(nLastBlockTime);
X(nTimeConnected);
X(nTimeOffset);
stats.addrName = GetAddrName();
diff --git a/src/net.h b/src/net.h
index 7a8abb401d..c72eada3ff 100644
--- a/src/net.h
+++ b/src/net.h
@@ -619,6 +619,8 @@ public:
bool fRelayTxes;
int64_t nLastSend;
int64_t nLastRecv;
+ int64_t nLastTXTime;
+ int64_t nLastBlockTime;
int64_t nTimeConnected;
int64_t nTimeOffset;
std::string addrName;
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 7b83583e41..adad428413 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -278,12 +278,6 @@ struct CNodeState {
const CService address;
//! Whether we have a fully established connection.
bool fCurrentlyConnected;
- //! Accumulated misbehaviour score for this peer.
- int nMisbehavior;
- //! Whether this peer should be disconnected and marked as discouraged (unless it has the noban permission).
- bool m_should_discourage;
- //! String name of this peer (debugging/logging purposes).
- const std::string name;
//! The best known block we know this peer has announced.
const CBlockIndex *pindexBestKnownBlock;
//! The hash of the last unknown block this peer has announced.
@@ -432,13 +426,10 @@ struct CNodeState {
//! Whether this peer relays txs via wtxid
bool m_wtxid_relay{false};
- CNodeState(CAddress addrIn, std::string addrNameIn, bool is_inbound, bool is_manual) :
- address(addrIn), name(std::move(addrNameIn)), m_is_inbound(is_inbound),
- m_is_manual_connection (is_manual)
+ CNodeState(CAddress addrIn, bool is_inbound, bool is_manual)
+ : address(addrIn), m_is_inbound(is_inbound), m_is_manual_connection(is_manual)
{
fCurrentlyConnected = false;
- nMisbehavior = 0;
- m_should_discourage = false;
pindexBestKnownBlock = nullptr;
hashLastUnknownBlock.SetNull();
pindexLastCommonBlock = nullptr;
@@ -476,6 +467,50 @@ static CNodeState *State(NodeId pnode) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
return &it->second;
}
+/**
+ * Data structure for an individual peer. This struct is not protected by
+ * cs_main since it does not contain validation-critical data.
+ *
+ * Memory is owned by shared pointers and this object is destructed when
+ * the refcount drops to zero.
+ *
+ * TODO: move most members from CNodeState to this structure.
+ * TODO: move remaining application-layer data members from CNode to this structure.
+ */
+struct Peer {
+ /** Same id as the CNode object for this peer */
+ const NodeId m_id{0};
+
+ /** Protects misbehavior data members */
+ Mutex m_misbehavior_mutex;
+ /** Accumulated misbehavior score for this peer */
+ int m_misbehavior_score GUARDED_BY(m_misbehavior_mutex){0};
+ /** Whether this peer should be disconnected and marked as discouraged (unless it has the noban permission). */
+ bool m_should_discourage GUARDED_BY(m_misbehavior_mutex){false};
+
+ Peer(NodeId id) : m_id(id) {}
+};
+
+using PeerRef = std::shared_ptr<Peer>;
+
+/**
+ * Map of all Peer objects, keyed by peer id. This map is protected
+ * by the global g_peer_mutex. Once a shared pointer reference is
+ * taken, the lock may be released. Individual fields are protected by
+ * their own locks.
+ */
+Mutex g_peer_mutex;
+static std::map<NodeId, PeerRef> g_peer_map GUARDED_BY(g_peer_mutex);
+
+/** Get a shared pointer to the Peer object.
+ * May return nullptr if the Peer object can't be found. */
+static PeerRef GetPeerRef(NodeId id)
+{
+ LOCK(g_peer_mutex);
+ auto it = g_peer_map.find(id);
+ return it != g_peer_map.end() ? it->second : nullptr;
+}
+
static void UpdatePreferredDownload(const CNode& node, CNodeState* state) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
nPreferredDownload -= state->fPreferredDownload;
@@ -841,10 +876,15 @@ void PeerLogicValidation::InitializeNode(CNode *pnode) {
NodeId nodeid = pnode->GetId();
{
LOCK(cs_main);
- mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, std::move(addrName), pnode->IsInboundConn(), pnode->IsManualConn()));
+ mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, pnode->IsInboundConn(), pnode->IsManualConn()));
+ }
+ {
+ PeerRef peer = std::make_shared<Peer>(nodeid);
+ LOCK(g_peer_mutex);
+ g_peer_map.emplace_hint(g_peer_map.end(), nodeid, std::move(peer));
}
if(!pnode->IsInboundConn())
- PushNodeVersion(*pnode, *connman, GetTime());
+ PushNodeVersion(*pnode, m_connman, GetTime());
}
void PeerLogicValidation::ReattemptInitialBroadcast(CScheduler& scheduler) const
@@ -855,7 +895,7 @@ void PeerLogicValidation::ReattemptInitialBroadcast(CScheduler& scheduler) const
// Sanity check: all unbroadcast txns should exist in the mempool
if (m_mempool.exists(elem.first)) {
LOCK(cs_main);
- RelayTransaction(elem.first, elem.second, *connman);
+ RelayTransaction(elem.first, elem.second, m_connman);
} else {
m_mempool.RemoveUnbroadcastTx(elem.first, true);
}
@@ -870,13 +910,21 @@ void PeerLogicValidation::ReattemptInitialBroadcast(CScheduler& scheduler) const
void PeerLogicValidation::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) {
fUpdateConnectionTime = false;
LOCK(cs_main);
+ int misbehavior{0};
+ {
+ PeerRef peer = GetPeerRef(nodeid);
+ assert(peer != nullptr);
+ misbehavior = WITH_LOCK(peer->m_misbehavior_mutex, return peer->m_misbehavior_score);
+ LOCK(g_peer_mutex);
+ g_peer_map.erase(nodeid);
+ }
CNodeState *state = State(nodeid);
assert(state != nullptr);
if (state->fSyncStarted)
nSyncStarted--;
- if (state->nMisbehavior == 0 && state->fCurrentlyConnected) {
+ if (misbehavior == 0 && state->fCurrentlyConnected) {
fUpdateConnectionTime = true;
}
@@ -906,17 +954,23 @@ void PeerLogicValidation::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTim
}
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
- LOCK(cs_main);
- CNodeState *state = State(nodeid);
- if (state == nullptr)
- return false;
- stats.nMisbehavior = state->nMisbehavior;
- stats.nSyncHeight = state->pindexBestKnownBlock ? state->pindexBestKnownBlock->nHeight : -1;
- stats.nCommonHeight = state->pindexLastCommonBlock ? state->pindexLastCommonBlock->nHeight : -1;
- for (const QueuedBlock& queue : state->vBlocksInFlight) {
- if (queue.pindex)
- stats.vHeightInFlight.push_back(queue.pindex->nHeight);
+ {
+ LOCK(cs_main);
+ CNodeState* state = State(nodeid);
+ if (state == nullptr)
+ return false;
+ stats.nSyncHeight = state->pindexBestKnownBlock ? state->pindexBestKnownBlock->nHeight : -1;
+ stats.nCommonHeight = state->pindexLastCommonBlock ? state->pindexLastCommonBlock->nHeight : -1;
+ for (const QueuedBlock& queue : state->vBlocksInFlight) {
+ if (queue.pindex)
+ stats.vHeightInFlight.push_back(queue.pindex->nHeight);
+ }
}
+
+ PeerRef peer = GetPeerRef(nodeid);
+ if (peer == nullptr) return false;
+ stats.m_misbehavior_score = WITH_LOCK(peer->m_misbehavior_mutex, return peer->m_misbehavior_score);
+
return true;
}
@@ -1060,21 +1114,21 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
* Increment peer's misbehavior score. If the new value >= DISCOURAGEMENT_THRESHOLD, mark the node
* to be discouraged, meaning the peer might be disconnected and added to the discouragement filter.
*/
-void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message)
{
assert(howmuch > 0);
- CNodeState* const state = State(pnode);
- if (state == nullptr) return;
+ PeerRef peer = GetPeerRef(pnode);
+ if (peer == nullptr) return;
- state->nMisbehavior += howmuch;
+ LOCK(peer->m_misbehavior_mutex);
+ peer->m_misbehavior_score += howmuch;
const std::string message_prefixed = message.empty() ? "" : (": " + message);
- if (state->nMisbehavior >= DISCOURAGEMENT_THRESHOLD && state->nMisbehavior - howmuch < DISCOURAGEMENT_THRESHOLD)
- {
- LogPrint(BCLog::NET, "Misbehaving: peer=%d (%d -> %d) DISCOURAGE THRESHOLD EXCEEDED%s\n", pnode, state->nMisbehavior - howmuch, state->nMisbehavior, message_prefixed);
- state->m_should_discourage = true;
+ if (peer->m_misbehavior_score >= DISCOURAGEMENT_THRESHOLD && peer->m_misbehavior_score - howmuch < DISCOURAGEMENT_THRESHOLD) {
+ LogPrint(BCLog::NET, "Misbehaving: peer=%d (%d -> %d) DISCOURAGE THRESHOLD EXCEEDED%s\n", pnode, peer->m_misbehavior_score - howmuch, peer->m_misbehavior_score, message_prefixed);
+ peer->m_should_discourage = true;
} else {
- LogPrint(BCLog::NET, "Misbehaving: peer=%d (%d -> %d)%s\n", pnode, state->nMisbehavior - howmuch, state->nMisbehavior, message_prefixed);
+ LogPrint(BCLog::NET, "Misbehaving: peer=%d (%d -> %d)%s\n", pnode, peer->m_misbehavior_score - howmuch, peer->m_misbehavior_score, message_prefixed);
}
}
@@ -1096,7 +1150,6 @@ static bool MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& s
case BlockValidationResult::BLOCK_CONSENSUS:
case BlockValidationResult::BLOCK_MUTATED:
if (!via_compact_block) {
- LOCK(cs_main);
Misbehaving(nodeid, 100, message);
return true;
}
@@ -1120,18 +1173,12 @@ static bool MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& s
case BlockValidationResult::BLOCK_INVALID_HEADER:
case BlockValidationResult::BLOCK_CHECKPOINT:
case BlockValidationResult::BLOCK_INVALID_PREV:
- {
- LOCK(cs_main);
- Misbehaving(nodeid, 100, message);
- }
+ Misbehaving(nodeid, 100, message);
return true;
// Conflicting (but not necessarily invalid) data or different policy:
case BlockValidationResult::BLOCK_MISSING_PREV:
- {
- // TODO: Handle this much more gracefully (10 DoS points is super arbitrary)
- LOCK(cs_main);
- Misbehaving(nodeid, 10, message);
- }
+ // TODO: Handle this much more gracefully (10 DoS points is super arbitrary)
+ Misbehaving(nodeid, 10, message);
return true;
case BlockValidationResult::BLOCK_RECENT_CONSENSUS_CHANGE:
case BlockValidationResult::BLOCK_TIME_FUTURE:
@@ -1155,11 +1202,8 @@ static bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state,
break;
// The node is providing invalid data:
case TxValidationResult::TX_CONSENSUS:
- {
- LOCK(cs_main);
- Misbehaving(nodeid, 100, message);
- return true;
- }
+ Misbehaving(nodeid, 100, message);
+ return true;
// Conflicting (but not necessarily invalid) data or different policy:
case TxValidationResult::TX_RECENT_CONSENSUS_CHANGE:
case TxValidationResult::TX_INPUTS_NOT_STANDARD:
@@ -1197,8 +1241,8 @@ static bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Para
(GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, consensusParams) < STALE_RELAY_AGE_LIMIT);
}
-PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn, BanMan* banman, CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool)
- : connman(connmanIn),
+PeerLogicValidation::PeerLogicValidation(CConnman& connman, BanMan* banman, CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool)
+ : m_connman(connman),
m_banman(banman),
m_chainman(chainman),
m_mempool(pool),
@@ -1326,7 +1370,7 @@ void PeerLogicValidation::NewPoWValidBlock(const CBlockIndex *pindex, const std:
fWitnessesPresentInMostRecentCompactBlock = fWitnessEnabled;
}
- connman->ForEachNode([this, &pcmpctblock, pindex, &msgMaker, fWitnessEnabled, &hashBlock](CNode* pnode) {
+ m_connman.ForEachNode([this, &pcmpctblock, pindex, &msgMaker, fWitnessEnabled, &hashBlock](CNode* pnode) {
AssertLockHeld(cs_main);
// TODO: Avoid the repeated-serialization here
@@ -1341,7 +1385,7 @@ void PeerLogicValidation::NewPoWValidBlock(const CBlockIndex *pindex, const std:
LogPrint(BCLog::NET, "%s sending header-and-ids %s to peer=%d\n", "PeerLogicValidation::NewPoWValidBlock",
hashBlock.ToString(), pnode->GetId());
- connman->PushMessage(pnode, msgMaker.Make(NetMsgType::CMPCTBLOCK, *pcmpctblock));
+ m_connman.PushMessage(pnode, msgMaker.Make(NetMsgType::CMPCTBLOCK, *pcmpctblock));
state.pindexBestHeaderSent = pindex;
}
});
@@ -1353,7 +1397,7 @@ void PeerLogicValidation::NewPoWValidBlock(const CBlockIndex *pindex, const std:
*/
void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
const int nNewHeight = pindexNew->nHeight;
- connman->SetBestHeight(nNewHeight);
+ m_connman.SetBestHeight(nNewHeight);
SetServiceFlagsIBDCache(!fInitialDownload);
if (!fInitialDownload) {
@@ -1370,7 +1414,7 @@ void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CB
}
}
// Relay inventory, but don't relay old inventory during initial block download.
- connman->ForEachNode([nNewHeight, &vHashes](CNode* pnode) {
+ m_connman.ForEachNode([nNewHeight, &vHashes](CNode* pnode) {
LOCK(pnode->cs_inventory);
if (nNewHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 0)) {
for (const uint256& hash : reverse_iterate(vHashes)) {
@@ -1378,7 +1422,7 @@ void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CB
}
}
});
- connman->WakeMessageHandler();
+ m_connman.WakeMessageHandler();
}
}
@@ -1409,7 +1453,7 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const BlockValidatio
!::ChainstateActive().IsInitialBlockDownload() &&
mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) {
if (it != mapBlockSource.end()) {
- MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first, *connman);
+ MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first, m_connman);
}
}
if (it != mapBlockSource.end())
@@ -1806,7 +1850,6 @@ inline void static SendBlockTransactions(const CBlock& block, const BlockTransac
BlockTransactions resp(req);
for (size_t i = 0; i < req.indexes.size(); i++) {
if (req.indexes[i] >= block.vtx.size()) {
- LOCK(cs_main);
Misbehaving(pfrom.GetId(), 100, "getblocktxn with out-of-bounds tx indices");
return;
}
@@ -2302,17 +2345,9 @@ static void ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv, const CChainPar
connman.PushMessage(&peer, std::move(msg));
}
-void ProcessMessage(
- CNode& pfrom,
- const std::string& msg_type,
- CDataStream& vRecv,
- const std::chrono::microseconds time_received,
- const CChainParams& chainparams,
- ChainstateManager& chainman,
- CTxMemPool& mempool,
- CConnman& connman,
- BanMan* banman,
- const std::atomic<bool>& interruptMsgProc)
+void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv,
+ const std::chrono::microseconds time_received,
+ const CChainParams& chainparams, const std::atomic<bool>& interruptMsgProc)
{
LogPrint(BCLog::NET, "received: %s (%u bytes) peer=%d\n", SanitizeString(msg_type), vRecv.size(), pfrom.GetId());
if (gArgs.IsArgSet("-dropmessagestest") && GetRand(gArgs.GetArg("-dropmessagestest", 0)) == 0)
@@ -2326,7 +2361,6 @@ void ProcessMessage(
// Each connection can only send one version message
if (pfrom.nVersion != 0)
{
- LOCK(cs_main);
Misbehaving(pfrom.GetId(), 1, "redundant version message");
return;
}
@@ -2348,7 +2382,7 @@ void ProcessMessage(
nServices = ServiceFlags(nServiceInt);
if (!pfrom.IsInboundConn())
{
- connman.SetServices(pfrom.addr, nServices);
+ m_connman.SetServices(pfrom.addr, nServices);
}
if (pfrom.ExpectServicesFromConn() && !HasAllDesirableServiceFlags(nServices))
{
@@ -2377,7 +2411,7 @@ void ProcessMessage(
if (!vRecv.empty())
vRecv >> fRelay;
// Disconnect if we connected to ourself
- if (pfrom.IsInboundConn() && !connman.CheckIncomingNonce(nNonce))
+ if (pfrom.IsInboundConn() && !m_connman.CheckIncomingNonce(nNonce))
{
LogPrintf("connected to self at %s, disconnecting\n", pfrom.addr.ToString());
pfrom.fDisconnect = true;
@@ -2391,13 +2425,13 @@ void ProcessMessage(
// Be shy and don't send version until we hear
if (pfrom.IsInboundConn())
- PushNodeVersion(pfrom, connman, GetAdjustedTime());
+ PushNodeVersion(pfrom, m_connman, GetAdjustedTime());
if (nVersion >= WTXID_RELAY_VERSION) {
- connman.PushMessage(&pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::WTXIDRELAY));
+ m_connman.PushMessage(&pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::WTXIDRELAY));
}
- connman.PushMessage(&pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERACK));
+ m_connman.PushMessage(&pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERACK));
pfrom.nServices = nServices;
pfrom.SetAddrLocal(addrMe);
@@ -2453,9 +2487,9 @@ void ProcessMessage(
}
// Get recent addresses
- connman.PushMessage(&pfrom, CNetMsgMaker(nSendVersion).Make(NetMsgType::GETADDR));
+ m_connman.PushMessage(&pfrom, CNetMsgMaker(nSendVersion).Make(NetMsgType::GETADDR));
pfrom.fGetAddr = true;
- connman.MarkAddressGood(pfrom.addr);
+ m_connman.MarkAddressGood(pfrom.addr);
}
std::string remoteAddr;
@@ -2474,7 +2508,7 @@ void ProcessMessage(
// If the peer is old enough to have the old alert system, send it the final alert.
if (pfrom.nVersion <= 70012) {
CDataStream finalAlert(ParseHex("60010000000000000000000000ffffff7f00000000ffffff7ffeffff7f01ffffff7f00000000ffffff7f00ffffff7f002f555247454e543a20416c657274206b657920636f6d70726f6d697365642c2075706772616465207265717569726564004630440220653febd6410f470f6bae11cad19c48413becb1ac2c17f908fd0fd53bdc3abd5202206d0e9c96fe88d4a0f01ed9dedae2b6f9e00da94cad0fecaae66ecf689bf71b50"), SER_NETWORK, PROTOCOL_VERSION);
- connman.PushMessage(&pfrom, CNetMsgMaker(nSendVersion).Make("alert", finalAlert));
+ m_connman.PushMessage(&pfrom, CNetMsgMaker(nSendVersion).Make("alert", finalAlert));
}
// Feeler connections exist only to verify if address is online.
@@ -2486,7 +2520,6 @@ void ProcessMessage(
if (pfrom.nVersion == 0) {
// Must have a version message before anything else
- LOCK(cs_main);
Misbehaving(pfrom.GetId(), 1, "non-version message before version handshake");
return;
}
@@ -2513,7 +2546,7 @@ void ProcessMessage(
// We send this to non-NODE NETWORK peers as well, because even
// non-NODE NETWORK peers can announce blocks (such as pruning
// nodes)
- connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDHEADERS));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDHEADERS));
}
if (pfrom.nVersion >= SHORT_IDS_BLOCKS_VERSION) {
// Tell our peer we are willing to provide version 1 or 2 cmpctblocks
@@ -2524,9 +2557,9 @@ void ProcessMessage(
bool fAnnounceUsingCMPCTBLOCK = false;
uint64_t nCMPCTBLOCKVersion = 2;
if (pfrom.GetLocalServices() & NODE_WITNESS)
- connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
nCMPCTBLOCKVersion = 1;
- connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
}
pfrom.fSuccessfullyConnected = true;
return;
@@ -2553,7 +2586,6 @@ void ProcessMessage(
if (!pfrom.fSuccessfullyConnected) {
// Must have a verack message before anything else
- LOCK(cs_main);
Misbehaving(pfrom.GetId(), 1, "non-verack message before version handshake");
return;
}
@@ -2567,7 +2599,6 @@ void ProcessMessage(
}
if (vAddr.size() > MAX_ADDR_TO_SEND)
{
- LOCK(cs_main);
Misbehaving(pfrom.GetId(), 20, strprintf("addr message size = %u", vAddr.size()));
return;
}
@@ -2590,7 +2621,7 @@ void ProcessMessage(
if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
addr.nTime = nNow - 5 * 24 * 60 * 60;
pfrom.AddAddressKnown(addr);
- if (banman && (banman->IsDiscouraged(addr) || banman->IsBanned(addr))) {
+ if (m_banman && (m_banman->IsDiscouraged(addr) || m_banman->IsBanned(addr))) {
// Do not process banned/discouraged addresses beyond remembering we received them
continue;
}
@@ -2598,13 +2629,13 @@ void ProcessMessage(
if (addr.nTime > nSince && !pfrom.fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
{
// Relay to a limited number of other nodes
- RelayAddress(addr, fReachable, connman);
+ RelayAddress(addr, fReachable, m_connman);
}
// Do not store addresses outside our network
if (fReachable)
vAddrOk.push_back(addr);
}
- connman.AddNewAddresses(vAddrOk, pfrom.addr, 2 * 60 * 60);
+ m_connman.AddNewAddresses(vAddrOk, pfrom.addr, 2 * 60 * 60);
if (vAddr.size() < 1000)
pfrom.fGetAddr = false;
if (pfrom.IsAddrFetchConn())
@@ -2646,7 +2677,6 @@ void ProcessMessage(
vRecv >> vInv;
if (vInv.size() > MAX_INV_SZ)
{
- LOCK(cs_main);
Misbehaving(pfrom.GetId(), 20, strprintf("inv message size = %u", vInv.size()));
return;
}
@@ -2680,7 +2710,7 @@ void ProcessMessage(
if (inv.IsMsgWtx()) continue;
}
- bool fAlreadyHave = AlreadyHave(inv, mempool);
+ bool fAlreadyHave = AlreadyHave(inv, m_mempool);
LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId());
if (inv.IsMsgTx()) {
@@ -2703,14 +2733,14 @@ void ProcessMessage(
LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol, disconnecting peer=%d\n", inv.hash.ToString(), pfrom.GetId());
pfrom.fDisconnect = true;
return;
- } else if (!fAlreadyHave && !chainman.ActiveChainstate().IsInitialBlockDownload()) {
+ } else if (!fAlreadyHave && !m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
RequestTx(State(pfrom.GetId()), ToGenTxid(inv), current_time);
}
}
}
if (best_block != nullptr) {
- connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), *best_block));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), *best_block));
LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, best_block->ToString(), pfrom.GetId());
}
@@ -2722,7 +2752,6 @@ void ProcessMessage(
vRecv >> vInv;
if (vInv.size() > MAX_INV_SZ)
{
- LOCK(cs_main);
Misbehaving(pfrom.GetId(), 20, strprintf("getdata message size = %u", vInv.size()));
return;
}
@@ -2734,7 +2763,7 @@ void ProcessMessage(
}
pfrom.vRecvGetData.insert(pfrom.vRecvGetData.end(), vInv.begin(), vInv.end());
- ProcessGetData(pfrom, chainparams, connman, mempool, interruptMsgProc);
+ ProcessGetData(pfrom, chainparams, m_connman, m_mempool, interruptMsgProc);
return;
}
@@ -2818,7 +2847,7 @@ void ProcessMessage(
// Unlock cs_most_recent_block to avoid cs_main lock inversion
}
if (recent_block) {
- SendBlockTransactions(*recent_block, req, pfrom, connman);
+ SendBlockTransactions(*recent_block, req, pfrom, m_connman);
return;
}
@@ -2851,7 +2880,7 @@ void ProcessMessage(
bool ret = ReadBlockFromDisk(block, pindex, chainparams.GetConsensus());
assert(ret);
- SendBlockTransactions(block, req, pfrom, connman);
+ SendBlockTransactions(block, req, pfrom, m_connman);
return;
}
@@ -2918,7 +2947,7 @@ void ProcessMessage(
// will re-announce the new block via headers (or compact blocks again)
// in the SendMessages logic.
nodestate->pindexBestHeaderSent = pindex ? pindex : ::ChainActive().Tip();
- connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders));
return;
}
@@ -2977,10 +3006,10 @@ void ProcessMessage(
// already; and an adversary can already relay us old transactions
// (older than our recency filter) if trying to DoS us, without any need
// for witness malleation.
- if (!AlreadyHave(CInv(MSG_WTX, wtxid), mempool) &&
- AcceptToMemoryPool(mempool, state, ptx, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
- mempool.check(&::ChainstateActive().CoinsTip());
- RelayTransaction(tx.GetHash(), tx.GetWitnessHash(), connman);
+ if (!AlreadyHave(CInv(MSG_WTX, wtxid), m_mempool) &&
+ AcceptToMemoryPool(m_mempool, state, ptx, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
+ m_mempool.check(&::ChainstateActive().CoinsTip());
+ RelayTransaction(tx.GetHash(), tx.GetWitnessHash(), m_connman);
for (unsigned int i = 0; i < tx.vout.size(); i++) {
auto it_by_prev = mapOrphanTransactionsByPrev.find(COutPoint(txid, i));
if (it_by_prev != mapOrphanTransactionsByPrev.end()) {
@@ -2995,10 +3024,10 @@ void ProcessMessage(
LogPrint(BCLog::MEMPOOL, "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n",
pfrom.GetId(),
tx.GetHash().ToString(),
- mempool.size(), mempool.DynamicMemoryUsage() / 1000);
+ m_mempool.size(), m_mempool.DynamicMemoryUsage() / 1000);
// Recursively process any orphan transactions that depended on this one
- ProcessOrphanTx(connman, mempool, pfrom.orphan_work_set, lRemovedTxn);
+ ProcessOrphanTx(m_connman, m_mempool, pfrom.orphan_work_set, lRemovedTxn);
}
else if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS)
{
@@ -3032,7 +3061,7 @@ void ProcessMessage(
// protocol for getting all unconfirmed parents.
CInv _inv(MSG_TX | nFetchFlags, parent_txid);
pfrom.AddKnownTx(parent_txid);
- if (!AlreadyHave(_inv, mempool)) RequestTx(State(pfrom.GetId()), ToGenTxid(_inv), current_time);
+ if (!AlreadyHave(_inv, m_mempool)) RequestTx(State(pfrom.GetId()), ToGenTxid(_inv), current_time);
}
AddOrphanTx(ptx, pfrom.GetId());
@@ -3093,11 +3122,11 @@ void ProcessMessage(
// if they were already in the mempool,
// allowing the node to function as a gateway for
// nodes hidden behind it.
- if (!mempool.exists(tx.GetHash())) {
+ if (!m_mempool.exists(tx.GetHash())) {
LogPrintf("Not relaying non-mempool transaction %s from forcerelay peer=%d\n", tx.GetHash().ToString(), pfrom.GetId());
} else {
LogPrintf("Force relaying tx %s from peer=%d\n", tx.GetHash().ToString(), pfrom.GetId());
- RelayTransaction(tx.GetHash(), tx.GetWitnessHash(), connman);
+ RelayTransaction(tx.GetHash(), tx.GetWitnessHash(), m_connman);
}
}
}
@@ -3150,7 +3179,7 @@ void ProcessMessage(
if (!LookupBlockIndex(cmpctblock.header.hashPrevBlock)) {
// Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers
if (!::ChainstateActive().IsInitialBlockDownload())
- connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), uint256()));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), uint256()));
return;
}
@@ -3161,7 +3190,7 @@ void ProcessMessage(
const CBlockIndex *pindex = nullptr;
BlockValidationState state;
- if (!chainman.ProcessNewBlockHeaders({cmpctblock.header}, state, chainparams, &pindex)) {
+ if (!m_chainman.ProcessNewBlockHeaders({cmpctblock.header}, state, chainparams, &pindex)) {
if (state.IsInvalid()) {
MaybePunishNodeForBlock(pfrom.GetId(), state, /*via_compact_block*/ true, "invalid header via cmpctblock");
return;
@@ -3211,7 +3240,7 @@ void ProcessMessage(
// so we just grab the block via normal getdata
std::vector<CInv> vInv(1);
vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash());
- connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
}
return;
}
@@ -3232,9 +3261,9 @@ void ProcessMessage(
if ((!fAlreadyInFlight && nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) ||
(fAlreadyInFlight && blockInFlightIt->second.first == pfrom.GetId())) {
std::list<QueuedBlock>::iterator* queuedBlockIt = nullptr;
- if (!MarkBlockAsInFlight(mempool, pfrom.GetId(), pindex->GetBlockHash(), pindex, &queuedBlockIt)) {
+ if (!MarkBlockAsInFlight(m_mempool, pfrom.GetId(), pindex->GetBlockHash(), pindex, &queuedBlockIt)) {
if (!(*queuedBlockIt)->partialBlock)
- (*queuedBlockIt)->partialBlock.reset(new PartiallyDownloadedBlock(&mempool));
+ (*queuedBlockIt)->partialBlock.reset(new PartiallyDownloadedBlock(&m_mempool));
else {
// The block was already in flight using compact blocks from the same peer
LogPrint(BCLog::NET, "Peer sent us compact block we were already syncing!\n");
@@ -3252,7 +3281,7 @@ void ProcessMessage(
// Duplicate txindexes, the block is now in-flight, so just request it
std::vector<CInv> vInv(1);
vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash());
- connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
return;
}
@@ -3269,7 +3298,7 @@ void ProcessMessage(
fProcessBLOCKTXN = true;
} else {
req.blockhash = pindex->GetBlockHash();
- connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETBLOCKTXN, req));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETBLOCKTXN, req));
}
} else {
// This block is either already in flight from a different
@@ -3277,7 +3306,7 @@ void ProcessMessage(
// download from.
// Optimistically try to reconstruct anyway since we might be
// able to without any round trips.
- PartiallyDownloadedBlock tempBlock(&mempool);
+ PartiallyDownloadedBlock tempBlock(&m_mempool);
ReadStatus status = tempBlock.InitData(cmpctblock, vExtraTxnForCompact);
if (status != READ_STATUS_OK) {
// TODO: don't ignore failures
@@ -3295,7 +3324,7 @@ void ProcessMessage(
// mempool will probably be useless - request the block normally
std::vector<CInv> vInv(1);
vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash());
- connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
return;
} else {
// If this was an announce-cmpctblock, we want the same treatment as a header message
@@ -3305,7 +3334,7 @@ void ProcessMessage(
} // cs_main
if (fProcessBLOCKTXN)
- return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, time_received, chainparams, chainman, mempool, connman, banman, interruptMsgProc);
+ return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, time_received, chainparams, interruptMsgProc);
if (fRevertToHeaderProcessing) {
// Headers received from HB compact block peers are permitted to be
@@ -3313,7 +3342,7 @@ void ProcessMessage(
// the peer if the header turns out to be for an invalid block.
// Note that if a peer tries to build on an invalid chain, that
// will be detected and the peer will be disconnected/discouraged.
- return ProcessHeadersMessage(pfrom, connman, chainman, mempool, {cmpctblock.header}, chainparams, /*via_compact_block=*/true);
+ return ProcessHeadersMessage(pfrom, m_connman, m_chainman, m_mempool, {cmpctblock.header}, chainparams, /*via_compact_block=*/true);
}
if (fBlockReconstructed) {
@@ -3333,7 +3362,7 @@ void ProcessMessage(
// we have a chain with at least nMinimumChainWork), and we ignore
// compact blocks with less work than our tip, it is safe to treat
// reconstructed compact blocks as having been requested.
- chainman.ProcessNewBlock(chainparams, pblock, /*fForceProcessing=*/true, &fNewBlock);
+ m_chainman.ProcessNewBlock(chainparams, pblock, /*fForceProcessing=*/true, &fNewBlock);
if (fNewBlock) {
pfrom.nLastBlockTime = GetTime();
} else {
@@ -3385,7 +3414,7 @@ void ProcessMessage(
// Might have collided, fall back to getdata now :(
std::vector<CInv> invs;
invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(pfrom), resp.blockhash));
- connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, invs));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, invs));
} else {
// Block is either okay, or possibly we received
// READ_STATUS_CHECKBLOCK_FAILED.
@@ -3423,7 +3452,7 @@ void ProcessMessage(
// disk-space attacks), but this should be safe due to the
// protections in the compact block handler -- see related comment
// in compact block optimistic reconstruction handling.
- chainman.ProcessNewBlock(chainparams, pblock, /*fForceProcessing=*/true, &fNewBlock);
+ m_chainman.ProcessNewBlock(chainparams, pblock, /*fForceProcessing=*/true, &fNewBlock);
if (fNewBlock) {
pfrom.nLastBlockTime = GetTime();
} else {
@@ -3447,7 +3476,6 @@ void ProcessMessage(
// Bypass the normal CBlock deserialization, as we don't want to risk deserializing 2000 full blocks.
unsigned int nCount = ReadCompactSize(vRecv);
if (nCount > MAX_HEADERS_RESULTS) {
- LOCK(cs_main);
Misbehaving(pfrom.GetId(), 20, strprintf("headers message size = %u", nCount));
return;
}
@@ -3457,7 +3485,7 @@ void ProcessMessage(
ReadCompactSize(vRecv); // ignore tx count; assume it is 0.
}
- return ProcessHeadersMessage(pfrom, connman, chainman, mempool, headers, chainparams, /*via_compact_block=*/false);
+ return ProcessHeadersMessage(pfrom, m_connman, m_chainman, m_mempool, headers, chainparams, /*via_compact_block=*/false);
}
if (msg_type == NetMsgType::BLOCK)
@@ -3486,7 +3514,7 @@ void ProcessMessage(
mapBlockSource.emplace(hash, std::make_pair(pfrom.GetId(), true));
}
bool fNewBlock = false;
- chainman.ProcessNewBlock(chainparams, pblock, forceProcessing, &fNewBlock);
+ m_chainman.ProcessNewBlock(chainparams, pblock, forceProcessing, &fNewBlock);
if (fNewBlock) {
pfrom.nLastBlockTime = GetTime();
} else {
@@ -3522,9 +3550,9 @@ void ProcessMessage(
pfrom.vAddrToSend.clear();
std::vector<CAddress> vAddr;
if (pfrom.HasPermission(PF_ADDR)) {
- vAddr = connman.GetAddresses(MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND);
+ vAddr = m_connman.GetAddresses(MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND);
} else {
- vAddr = connman.GetAddresses(pfrom.addr.GetNetwork(), MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND);
+ vAddr = m_connman.GetAddresses(pfrom.addr.GetNetwork(), MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND);
}
FastRandomContext insecure_rand;
for (const CAddress &addr : vAddr) {
@@ -3544,7 +3572,7 @@ void ProcessMessage(
return;
}
- if (connman.OutboundTargetReached(false) && !pfrom.HasPermission(PF_MEMPOOL))
+ if (m_connman.OutboundTargetReached(false) && !pfrom.HasPermission(PF_MEMPOOL))
{
if (!pfrom.HasPermission(PF_NOBAN))
{
@@ -3577,7 +3605,7 @@ void ProcessMessage(
// it, if the remote node sends a ping once per second and this node takes 5
// seconds to respond to each, the 5th ping the remote sends would appear to
// return very quickly.
- connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::PONG, nonce));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::PONG, nonce));
}
return;
}
@@ -3649,7 +3677,6 @@ void ProcessMessage(
if (!filter.IsWithinSizeConstraints())
{
// There is no excuse for sending a too-large filter
- LOCK(cs_main);
Misbehaving(pfrom.GetId(), 100, "too-large bloom filter");
}
else if (pfrom.m_tx_relay != nullptr)
@@ -3683,7 +3710,6 @@ void ProcessMessage(
}
}
if (bad) {
- LOCK(cs_main);
Misbehaving(pfrom.GetId(), 100, "bad filteradd message");
}
return;
@@ -3717,17 +3743,17 @@ void ProcessMessage(
}
if (msg_type == NetMsgType::GETCFILTERS) {
- ProcessGetCFilters(pfrom, vRecv, chainparams, connman);
+ ProcessGetCFilters(pfrom, vRecv, chainparams, m_connman);
return;
}
if (msg_type == NetMsgType::GETCFHEADERS) {
- ProcessGetCFHeaders(pfrom, vRecv, chainparams, connman);
+ ProcessGetCFHeaders(pfrom, vRecv, chainparams, m_connman);
return;
}
if (msg_type == NetMsgType::GETCFCHECKPT) {
- ProcessGetCFCheckPt(pfrom, vRecv, chainparams, connman);
+ ProcessGetCFCheckPt(pfrom, vRecv, chainparams, m_connman);
return;
}
@@ -3769,15 +3795,17 @@ void ProcessMessage(
bool PeerLogicValidation::MaybeDiscourageAndDisconnect(CNode& pnode)
{
const NodeId peer_id{pnode.GetId()};
+ PeerRef peer = GetPeerRef(peer_id);
+ if (peer == nullptr) return false;
+
{
- LOCK(cs_main);
- CNodeState& state = *State(peer_id);
+ LOCK(peer->m_misbehavior_mutex);
// There's nothing to do if the m_should_discourage flag isn't set
- if (!state.m_should_discourage) return false;
+ if (!peer->m_should_discourage) return false;
- state.m_should_discourage = false;
- } // cs_main
+ peer->m_should_discourage = false;
+ } // peer.m_misbehavior_mutex
if (pnode.HasPermission(PF_NOBAN)) {
// We never disconnect or discourage peers for bad behavior if they have the NOBAN permission flag
@@ -3802,7 +3830,7 @@ bool PeerLogicValidation::MaybeDiscourageAndDisconnect(CNode& pnode)
// Normal case: Disconnect the peer and discourage all nodes sharing the address
LogPrintf("Disconnecting and discouraging peer %d!\n", peer_id);
if (m_banman) m_banman->Discourage(pnode.addr);
- connman->DisconnectNode(pnode.addr);
+ m_connman.DisconnectNode(pnode.addr);
return true;
}
@@ -3820,12 +3848,12 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
bool fMoreWork = false;
if (!pfrom->vRecvGetData.empty())
- ProcessGetData(*pfrom, chainparams, *connman, m_mempool, interruptMsgProc);
+ ProcessGetData(*pfrom, chainparams, m_connman, m_mempool, interruptMsgProc);
if (!pfrom->orphan_work_set.empty()) {
std::list<CTransactionRef> removed_txn;
LOCK2(cs_main, g_cs_orphans);
- ProcessOrphanTx(*connman, m_mempool, pfrom->orphan_work_set, removed_txn);
+ ProcessOrphanTx(m_connman, m_mempool, pfrom->orphan_work_set, removed_txn);
for (const CTransactionRef& removedTx : removed_txn) {
AddToCompactExtraTransactions(removedTx);
}
@@ -3851,7 +3879,7 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
// Just take one message
msgs.splice(msgs.begin(), pfrom->vProcessMsg, pfrom->vProcessMsg.begin());
pfrom->nProcessQueueSize -= msgs.front().m_raw_message_size;
- pfrom->fPauseRecv = pfrom->nProcessQueueSize > connman->GetReceiveFloodSize();
+ pfrom->fPauseRecv = pfrom->nProcessQueueSize > m_connman.GetReceiveFloodSize();
fMoreWork = !pfrom->vProcessMsg.empty();
}
CNetMessage& msg(msgs.front());
@@ -3885,7 +3913,7 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
}
try {
- ProcessMessage(*pfrom, msg_type, vRecv, msg.m_time, chainparams, m_chainman, m_mempool, *connman, m_banman, interruptMsgProc);
+ ProcessMessage(*pfrom, msg_type, vRecv, msg.m_time, chainparams, interruptMsgProc);
if (interruptMsgProc)
return false;
if (!pfrom->vRecvGetData.empty())
@@ -3938,7 +3966,7 @@ void PeerLogicValidation::ConsiderEviction(CNode& pto, int64_t time_in_seconds)
} else {
assert(state.m_chain_sync.m_work_header);
LogPrint(BCLog::NET, "sending getheaders to outbound peer=%d to verify chain work (current best known block:%s, benchmark blockhash: %s)\n", pto.GetId(), state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : "<none>", state.m_chain_sync.m_work_header->GetBlockHash().ToString());
- connman->PushMessage(&pto, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(state.m_chain_sync.m_work_header->pprev), uint256()));
+ m_connman.PushMessage(&pto, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(state.m_chain_sync.m_work_header->pprev), uint256()));
state.m_chain_sync.m_sent_getheaders = true;
constexpr int64_t HEADERS_RESPONSE_TIME = 120; // 2 minutes
// Bump the timeout to allow a response, which could clear the timeout
@@ -3955,7 +3983,7 @@ void PeerLogicValidation::ConsiderEviction(CNode& pto, int64_t time_in_seconds)
void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds)
{
// Check whether we have too many outbound peers
- int extra_peers = connman->GetExtraOutboundCount();
+ int extra_peers = m_connman.GetExtraOutboundCount();
if (extra_peers > 0) {
// If we have more outbound peers than we target, disconnect one.
// Pick the outbound peer that least recently announced
@@ -3964,7 +3992,7 @@ void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds)
NodeId worst_peer = -1;
int64_t oldest_block_announcement = std::numeric_limits<int64_t>::max();
- connman->ForEachNode([&](CNode* pnode) {
+ m_connman.ForEachNode([&](CNode* pnode) {
AssertLockHeld(cs_main);
// Ignore non-outbound peers, or nodes marked for disconnect already
@@ -3981,7 +4009,7 @@ void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds)
}
});
if (worst_peer != -1) {
- bool disconnected = connman->ForNode(worst_peer, [&](CNode *pnode) {
+ bool disconnected = m_connman.ForNode(worst_peer, [&](CNode *pnode) {
AssertLockHeld(cs_main);
// Only disconnect a peer that has been connected to us for
@@ -4005,7 +4033,7 @@ void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds)
// detected a stale tip. Don't try any more extra peers until
// we next detect a stale tip, to limit the load we put on the
// network from these extra connections.
- connman->SetTryNewOutboundPeer(false);
+ m_connman.SetTryNewOutboundPeer(false);
}
}
}
@@ -4015,8 +4043,6 @@ void PeerLogicValidation::CheckForStaleTipAndEvictPeers(const Consensus::Params
{
LOCK(cs_main);
- if (connman == nullptr) return;
-
int64_t time_in_seconds = GetTime();
EvictExtraOutboundPeers(time_in_seconds);
@@ -4024,11 +4050,11 @@ void PeerLogicValidation::CheckForStaleTipAndEvictPeers(const Consensus::Params
if (time_in_seconds > m_stale_tip_check_time) {
// Check whether our tip is stale, and if so, allow using an extra
// outbound peer
- if (!fImporting && !fReindex && connman->GetNetworkActive() && connman->GetUseAddrmanOutgoing() && TipMayBeStale(consensusParams)) {
+ if (!fImporting && !fReindex && m_connman.GetNetworkActive() && m_connman.GetUseAddrmanOutgoing() && TipMayBeStale(consensusParams)) {
LogPrintf("Potential stale tip detected, will try using extra outbound peer (last tip update: %d seconds ago)\n", time_in_seconds - g_last_tip_update);
- connman->SetTryNewOutboundPeer(true);
- } else if (connman->GetTryNewOutboundPeer()) {
- connman->SetTryNewOutboundPeer(false);
+ m_connman.SetTryNewOutboundPeer(true);
+ } else if (m_connman.GetTryNewOutboundPeer()) {
+ m_connman.SetTryNewOutboundPeer(false);
}
m_stale_tip_check_time = time_in_seconds + STALE_CHECK_INTERVAL;
}
@@ -4091,11 +4117,11 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
pto->m_ping_start = GetTime<std::chrono::microseconds>();
if (pto->nVersion > BIP0031_VERSION) {
pto->nPingNonceSent = nonce;
- connman->PushMessage(pto, msgMaker.Make(NetMsgType::PING, nonce));
+ m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::PING, nonce));
} else {
// Peer is too old to support ping command with nonce, pong will never arrive.
pto->nPingNonceSent = 0;
- connman->PushMessage(pto, msgMaker.Make(NetMsgType::PING));
+ m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::PING));
}
}
@@ -4130,14 +4156,14 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
// receiver rejects addr messages larger than MAX_ADDR_TO_SEND
if (vAddr.size() >= MAX_ADDR_TO_SEND)
{
- connman->PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr));
+ m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr));
vAddr.clear();
}
}
}
pto->vAddrToSend.clear();
if (!vAddr.empty())
- connman->PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr));
+ m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr));
// we only send the big addr message once
if (pto->vAddrToSend.capacity() > 40)
pto->vAddrToSend.shrink_to_fit();
@@ -4164,7 +4190,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
if (pindexStart->pprev)
pindexStart = pindexStart->pprev;
LogPrint(BCLog::NET, "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->GetId(), pto->nStartingHeight);
- connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexStart), uint256()));
+ m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexStart), uint256()));
}
}
@@ -4248,10 +4274,10 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
LOCK(cs_most_recent_block);
if (most_recent_block_hash == pBestIndex->GetBlockHash()) {
if (state.fWantsCmpctWitness || !fWitnessesPresentInMostRecentCompactBlock)
- connman->PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *most_recent_compact_block));
+ m_connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *most_recent_compact_block));
else {
CBlockHeaderAndShortTxIDs cmpctblock(*most_recent_block, state.fWantsCmpctWitness);
- connman->PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
+ m_connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
}
fGotBlockFromCache = true;
}
@@ -4261,7 +4287,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
bool ret = ReadBlockFromDisk(block, pBestIndex, consensusParams);
assert(ret);
CBlockHeaderAndShortTxIDs cmpctblock(block, state.fWantsCmpctWitness);
- connman->PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
+ m_connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
}
state.pindexBestHeaderSent = pBestIndex;
} else if (state.fPreferHeaders) {
@@ -4274,7 +4300,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
LogPrint(BCLog::NET, "%s: sending header %s to peer=%d\n", __func__,
vHeaders.front().GetHash().ToString(), pto->GetId());
}
- connman->PushMessage(pto, msgMaker.Make(NetMsgType::HEADERS, vHeaders));
+ m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::HEADERS, vHeaders));
state.pindexBestHeaderSent = pBestIndex;
} else
fRevertToInv = true;
@@ -4319,7 +4345,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
for (const uint256& hash : pto->vInventoryBlockToSend) {
vInv.push_back(CInv(MSG_BLOCK, hash));
if (vInv.size() == MAX_INV_SZ) {
- connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
+ m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
vInv.clear();
}
}
@@ -4332,7 +4358,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
if (pto->m_tx_relay->nNextInvSend < current_time) {
fSendTrickle = true;
if (pto->IsInboundConn()) {
- pto->m_tx_relay->nNextInvSend = std::chrono::microseconds{connman->PoissonNextSendInbound(nNow, INVENTORY_BROADCAST_INTERVAL)};
+ pto->m_tx_relay->nNextInvSend = std::chrono::microseconds{m_connman.PoissonNextSendInbound(nNow, INVENTORY_BROADCAST_INTERVAL)};
} else {
// Use half the delay for outbound peers, as there is less privacy concern for them.
pto->m_tx_relay->nNextInvSend = PoissonNextSend(current_time, std::chrono::seconds{INVENTORY_BROADCAST_INTERVAL >> 1});
@@ -4372,7 +4398,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
// Responses to MEMPOOL requests bypass the m_recently_announced_invs filter.
vInv.push_back(inv);
if (vInv.size() == MAX_INV_SZ) {
- connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
+ m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
vInv.clear();
}
}
@@ -4448,7 +4474,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
}
}
if (vInv.size() == MAX_INV_SZ) {
- connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
+ m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
vInv.clear();
}
pto->m_tx_relay->filterInventoryKnown.insert(hash);
@@ -4465,7 +4491,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
}
}
if (!vInv.empty())
- connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
+ m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
// Detect whether we're stalling
current_time = GetTime<std::chrono::microseconds>();
@@ -4593,7 +4619,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
LogPrint(BCLog::NET, "Requesting %s peer=%d\n", inv.ToString(), pto->GetId());
vGetData.push_back(inv);
if (vGetData.size() >= MAX_GETDATA_SZ) {
- connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
+ m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
vGetData.clear();
}
UpdateTxRequestTime(gtxid, current_time);
@@ -4623,7 +4649,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
if (!vGetData.empty())
- connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
+ m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
//
// Message: feefilter
@@ -4651,7 +4677,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
// We always have a fee filter of at least minRelayTxFee
filterToSend = std::max(filterToSend, ::minRelayTxFee.GetFeePerK());
if (filterToSend != pto->m_tx_relay->lastSentFeeFilter) {
- connman->PushMessage(pto, msgMaker.Make(NetMsgType::FEEFILTER, filterToSend));
+ m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::FEEFILTER, filterToSend));
pto->m_tx_relay->lastSentFeeFilter = filterToSend;
}
pto->m_tx_relay->nextSendTimeFeeFilter = PoissonNextSend(timeNow, AVG_FEEFILTER_BROADCAST_INTERVAL);
diff --git a/src/net_processing.h b/src/net_processing.h
index 2d98714122..4f1c52fc17 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -11,6 +11,7 @@
#include <sync.h>
#include <validationinterface.h>
+class CChainParams;
class CTxMemPool;
class ChainstateManager;
@@ -28,7 +29,7 @@ static const int DISCOURAGEMENT_THRESHOLD{100};
class PeerLogicValidation final : public CValidationInterface, public NetEventsInterface {
private:
- CConnman* const connman;
+ CConnman& m_connman;
/** Pointer to this node's banman. May be nullptr - check existence before dereferencing. */
BanMan* const m_banman;
ChainstateManager& m_chainman;
@@ -37,7 +38,7 @@ private:
bool MaybeDiscourageAndDisconnect(CNode& pnode);
public:
- PeerLogicValidation(CConnman* connman, BanMan* banman, CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool);
+ PeerLogicValidation(CConnman& connman, BanMan* banman, CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool);
/**
* Overridden from CValidationInterface.
@@ -85,12 +86,18 @@ public:
/** Retrieve unbroadcast transactions from the mempool and reattempt sending to peers */
void ReattemptInitialBroadcast(CScheduler& scheduler) const;
+ /** Process a single message from a peer. Public for fuzz testing */
+ void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv,
+ const std::chrono::microseconds time_received, const CChainParams& chainparams,
+ const std::atomic<bool>& interruptMsgProc);
+
private:
int64_t m_stale_tip_check_time; //!< Next time to check for stale tip
+
};
struct CNodeStateStats {
- int nMisbehavior = 0;
+ int m_misbehavior_score = 0;
int nSyncHeight = -1;
int nCommonHeight = -1;
std::vector<int> vHeightInFlight;
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index d29aed6c8b..b50cf74069 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -3,79 +3,91 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <cstdint>
#include <netaddress.h>
+
#include <hash.h>
+#include <tinyformat.h>
#include <util/strencodings.h>
#include <util/asmap.h>
-#include <tinyformat.h>
-static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
-static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43};
+#include <algorithm>
+#include <array>
+#include <cstdint>
+#include <iterator>
+#include <tuple>
-// 0xFD + sha256("bitcoin")[0:5]
-static const unsigned char g_internal_prefix[] = { 0xFD, 0x6B, 0x88, 0xC0, 0x87, 0x24 };
+constexpr size_t CNetAddr::V1_SERIALIZATION_SIZE;
/**
* Construct an unspecified IPv6 network address (::/128).
*
* @note This address is considered invalid by CNetAddr::IsValid()
*/
-CNetAddr::CNetAddr()
-{
- memset(ip, 0, sizeof(ip));
-}
+CNetAddr::CNetAddr() {}
void CNetAddr::SetIP(const CNetAddr& ipIn)
{
+ // Size check.
+ switch (ipIn.m_net) {
+ case NET_IPV4:
+ assert(ipIn.m_addr.size() == ADDR_IPV4_SIZE);
+ break;
+ case NET_IPV6:
+ assert(ipIn.m_addr.size() == ADDR_IPV6_SIZE);
+ break;
+ case NET_ONION:
+ assert(ipIn.m_addr.size() == ADDR_TORV2_SIZE);
+ break;
+ case NET_INTERNAL:
+ assert(ipIn.m_addr.size() == ADDR_INTERNAL_SIZE);
+ break;
+ case NET_UNROUTABLE:
+ case NET_MAX:
+ assert(false);
+ } // no default case, so the compiler can warn about missing cases
+
m_net = ipIn.m_net;
- memcpy(ip, ipIn.ip, sizeof(ip));
+ m_addr = ipIn.m_addr;
+}
+
+template <typename T1, size_t PREFIX_LEN>
+inline bool HasPrefix(const T1& obj, const std::array<uint8_t, PREFIX_LEN>& prefix)
+{
+ return obj.size() >= PREFIX_LEN &&
+ std::equal(std::begin(prefix), std::end(prefix), std::begin(obj));
}
-void CNetAddr::SetLegacyIPv6(const uint8_t ipv6[16])
+void CNetAddr::SetLegacyIPv6(Span<const uint8_t> ipv6)
{
- if (memcmp(ipv6, pchIPv4, sizeof(pchIPv4)) == 0) {
+ assert(ipv6.size() == ADDR_IPV6_SIZE);
+
+ size_t skip{0};
+
+ if (HasPrefix(ipv6, IPV4_IN_IPV6_PREFIX)) {
+ // IPv4-in-IPv6
m_net = NET_IPV4;
- } else if (memcmp(ipv6, pchOnionCat, sizeof(pchOnionCat)) == 0) {
+ skip = sizeof(IPV4_IN_IPV6_PREFIX);
+ } else if (HasPrefix(ipv6, TORV2_IN_IPV6_PREFIX)) {
+ // TORv2-in-IPv6
m_net = NET_ONION;
- } else if (memcmp(ipv6, g_internal_prefix, sizeof(g_internal_prefix)) == 0) {
+ skip = sizeof(TORV2_IN_IPV6_PREFIX);
+ } else if (HasPrefix(ipv6, INTERNAL_IN_IPV6_PREFIX)) {
+ // Internal-in-IPv6
m_net = NET_INTERNAL;
+ skip = sizeof(INTERNAL_IN_IPV6_PREFIX);
} else {
+ // IPv6
m_net = NET_IPV6;
}
- memcpy(ip, ipv6, 16);
-}
-void CNetAddr::SetRaw(Network network, const uint8_t *ip_in)
-{
- switch(network)
- {
- case NET_IPV4:
- m_net = NET_IPV4;
- memcpy(ip, pchIPv4, 12);
- memcpy(ip+12, ip_in, 4);
- break;
- case NET_IPV6:
- SetLegacyIPv6(ip_in);
- break;
- default:
- assert(!"invalid network");
- }
+ m_addr.assign(ipv6.begin() + skip, ipv6.end());
}
/**
- * Try to make this a dummy address that maps the specified name into IPv6 like
- * so: (0xFD + %sha256("bitcoin")[0:5]) + %sha256(name)[0:10]. Such dummy
- * addresses have a prefix of fd6b:88c0:8724::/48 and are guaranteed to not be
- * publicly routable as it falls under RFC4193's fc00::/7 subnet allocated to
- * unique-local addresses.
- *
- * CAddrMan uses these fake addresses to keep track of which DNS seeds were
- * used.
- *
+ * Create an "internal" address that represents a name or FQDN. CAddrMan uses
+ * these fake addresses to keep track of which DNS seeds were used.
* @returns Whether or not the operation was successful.
- *
- * @see CNetAddr::IsInternal(), CNetAddr::IsRFC4193()
+ * @see NET_INTERNAL, INTERNAL_IN_IPV6_PREFIX, CNetAddr::IsInternal(), CNetAddr::IsRFC4193()
*/
bool CNetAddr::SetInternal(const std::string &name)
{
@@ -85,31 +97,26 @@ bool CNetAddr::SetInternal(const std::string &name)
m_net = NET_INTERNAL;
unsigned char hash[32] = {};
CSHA256().Write((const unsigned char*)name.data(), name.size()).Finalize(hash);
- memcpy(ip, g_internal_prefix, sizeof(g_internal_prefix));
- memcpy(ip + sizeof(g_internal_prefix), hash, sizeof(ip) - sizeof(g_internal_prefix));
+ m_addr.assign(hash, hash + ADDR_INTERNAL_SIZE);
return true;
}
/**
- * Try to make this a dummy address that maps the specified onion address into
- * IPv6 using OnionCat's range and encoding. Such dummy addresses have a prefix
- * of fd87:d87e:eb43::/48 and are guaranteed to not be publicly routable as they
- * fall under RFC4193's fc00::/7 subnet allocated to unique-local addresses.
+ * Parse a TORv2 address and set this object to it.
*
* @returns Whether or not the operation was successful.
*
- * @see CNetAddr::IsTor(), CNetAddr::IsRFC4193()
+ * @see CNetAddr::IsTor()
*/
bool CNetAddr::SetSpecial(const std::string &strName)
{
if (strName.size()>6 && strName.substr(strName.size() - 6, 6) == ".onion") {
std::vector<unsigned char> vchAddr = DecodeBase32(strName.substr(0, strName.size() - 6).c_str());
- if (vchAddr.size() != 16-sizeof(pchOnionCat))
+ if (vchAddr.size() != ADDR_TORV2_SIZE) {
return false;
+ }
m_net = NET_ONION;
- memcpy(ip, pchOnionCat, sizeof(pchOnionCat));
- for (unsigned int i=0; i<16-sizeof(pchOnionCat); i++)
- ip[i + sizeof(pchOnionCat)] = vchAddr[i];
+ m_addr.assign(vchAddr.begin(), vchAddr.end());
return true;
}
return false;
@@ -117,28 +124,23 @@ bool CNetAddr::SetSpecial(const std::string &strName)
CNetAddr::CNetAddr(const struct in_addr& ipv4Addr)
{
- SetRaw(NET_IPV4, (const uint8_t*)&ipv4Addr);
+ m_net = NET_IPV4;
+ const uint8_t* ptr = reinterpret_cast<const uint8_t*>(&ipv4Addr);
+ m_addr.assign(ptr, ptr + ADDR_IPV4_SIZE);
}
CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr, const uint32_t scope)
{
- SetRaw(NET_IPV6, (const uint8_t*)&ipv6Addr);
+ SetLegacyIPv6(Span<const uint8_t>(reinterpret_cast<const uint8_t*>(&ipv6Addr), sizeof(ipv6Addr)));
scopeId = scope;
}
-unsigned int CNetAddr::GetByte(int n) const
-{
- return ip[15-n];
-}
-
bool CNetAddr::IsBindAny() const
{
- const int cmplen = IsIPv4() ? 4 : 16;
- for (int i = 0; i < cmplen; ++i) {
- if (GetByte(i)) return false;
+ if (!IsIPv4() && !IsIPv6()) {
+ return false;
}
-
- return true;
+ return std::all_of(m_addr.begin(), m_addr.end(), [](uint8_t b) { return b == 0; });
}
bool CNetAddr::IsIPv4() const { return m_net == NET_IPV4; }
@@ -148,88 +150,88 @@ bool CNetAddr::IsIPv6() const { return m_net == NET_IPV6; }
bool CNetAddr::IsRFC1918() const
{
return IsIPv4() && (
- GetByte(3) == 10 ||
- (GetByte(3) == 192 && GetByte(2) == 168) ||
- (GetByte(3) == 172 && (GetByte(2) >= 16 && GetByte(2) <= 31)));
+ m_addr[0] == 10 ||
+ (m_addr[0] == 192 && m_addr[1] == 168) ||
+ (m_addr[0] == 172 && m_addr[1] >= 16 && m_addr[1] <= 31));
}
bool CNetAddr::IsRFC2544() const
{
- return IsIPv4() && GetByte(3) == 198 && (GetByte(2) == 18 || GetByte(2) == 19);
+ return IsIPv4() && m_addr[0] == 198 && (m_addr[1] == 18 || m_addr[1] == 19);
}
bool CNetAddr::IsRFC3927() const
{
- return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254);
+ return IsIPv4() && HasPrefix(m_addr, std::array<uint8_t, 2>{169, 254});
}
bool CNetAddr::IsRFC6598() const
{
- return IsIPv4() && GetByte(3) == 100 && GetByte(2) >= 64 && GetByte(2) <= 127;
+ return IsIPv4() && m_addr[0] == 100 && m_addr[1] >= 64 && m_addr[1] <= 127;
}
bool CNetAddr::IsRFC5737() const
{
- return IsIPv4() && ((GetByte(3) == 192 && GetByte(2) == 0 && GetByte(1) == 2) ||
- (GetByte(3) == 198 && GetByte(2) == 51 && GetByte(1) == 100) ||
- (GetByte(3) == 203 && GetByte(2) == 0 && GetByte(1) == 113));
+ return IsIPv4() && (HasPrefix(m_addr, std::array<uint8_t, 3>{192, 0, 2}) ||
+ HasPrefix(m_addr, std::array<uint8_t, 3>{198, 51, 100}) ||
+ HasPrefix(m_addr, std::array<uint8_t, 3>{203, 0, 113}));
}
bool CNetAddr::IsRFC3849() const
{
- return IsIPv6() && GetByte(15) == 0x20 && GetByte(14) == 0x01 &&
- GetByte(13) == 0x0D && GetByte(12) == 0xB8;
+ return IsIPv6() && HasPrefix(m_addr, std::array<uint8_t, 4>{0x20, 0x01, 0x0D, 0xB8});
}
bool CNetAddr::IsRFC3964() const
{
- return IsIPv6() && GetByte(15) == 0x20 && GetByte(14) == 0x02;
+ return IsIPv6() && HasPrefix(m_addr, std::array<uint8_t, 2>{0x20, 0x02});
}
bool CNetAddr::IsRFC6052() const
{
- static const unsigned char pchRFC6052[] = {0,0x64,0xFF,0x9B,0,0,0,0,0,0,0,0};
- return IsIPv6() && memcmp(ip, pchRFC6052, sizeof(pchRFC6052)) == 0;
+ return IsIPv6() &&
+ HasPrefix(m_addr, std::array<uint8_t, 12>{0x00, 0x64, 0xFF, 0x9B, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
}
bool CNetAddr::IsRFC4380() const
{
- return IsIPv6() && GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0 &&
- GetByte(12) == 0;
+ return IsIPv6() && HasPrefix(m_addr, std::array<uint8_t, 4>{0x20, 0x01, 0x00, 0x00});
}
bool CNetAddr::IsRFC4862() const
{
- static const unsigned char pchRFC4862[] = {0xFE,0x80,0,0,0,0,0,0};
- return IsIPv6() && memcmp(ip, pchRFC4862, sizeof(pchRFC4862)) == 0;
+ return IsIPv6() && HasPrefix(m_addr, std::array<uint8_t, 8>{0xFE, 0x80, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00});
}
bool CNetAddr::IsRFC4193() const
{
- return IsIPv6() && (GetByte(15) & 0xFE) == 0xFC;
+ return IsIPv6() && (m_addr[0] & 0xFE) == 0xFC;
}
bool CNetAddr::IsRFC6145() const
{
- static const unsigned char pchRFC6145[] = {0,0,0,0,0,0,0,0,0xFF,0xFF,0,0};
- return IsIPv6() && memcmp(ip, pchRFC6145, sizeof(pchRFC6145)) == 0;
+ return IsIPv6() &&
+ HasPrefix(m_addr, std::array<uint8_t, 12>{0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00});
}
bool CNetAddr::IsRFC4843() const
{
- return IsIPv6() && GetByte(15) == 0x20 && GetByte(14) == 0x01 &&
- GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10;
+ return IsIPv6() && HasPrefix(m_addr, std::array<uint8_t, 3>{0x20, 0x01, 0x00}) &&
+ (m_addr[3] & 0xF0) == 0x10;
}
bool CNetAddr::IsRFC7343() const
{
- return IsIPv6() && GetByte(15) == 0x20 && GetByte(14) == 0x01 &&
- GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x20;
+ return IsIPv6() && HasPrefix(m_addr, std::array<uint8_t, 3>{0x20, 0x01, 0x00}) &&
+ (m_addr[3] & 0xF0) == 0x20;
}
bool CNetAddr::IsHeNet() const
{
- return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x04 && GetByte(12) == 0x70);
+ return IsIPv6() && HasPrefix(m_addr, std::array<uint8_t, 4>{0x20, 0x01, 0x04, 0x70});
}
/**
@@ -243,13 +245,15 @@ bool CNetAddr::IsTor() const { return m_net == NET_ONION; }
bool CNetAddr::IsLocal() const
{
// IPv4 loopback (127.0.0.0/8 or 0.0.0.0/8)
- if (IsIPv4() && (GetByte(3) == 127 || GetByte(3) == 0))
+ if (IsIPv4() && (m_addr[0] == 127 || m_addr[0] == 0)) {
return true;
+ }
// IPv6 loopback (::1/128)
static const unsigned char pchLocal[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
- if (IsIPv6() && memcmp(ip, pchLocal, 16) == 0)
+ if (IsIPv6() && memcmp(m_addr.data(), pchLocal, sizeof(pchLocal)) == 0) {
return true;
+ }
return false;
}
@@ -266,19 +270,11 @@ bool CNetAddr::IsLocal() const
*/
bool CNetAddr::IsValid() const
{
- // Cleanup 3-byte shifted addresses caused by garbage in size field
- // of addr messages from versions before 0.2.9 checksum.
- // Two consecutive addr messages look like this:
- // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 addr26 addr26...
- // so if the first length field is garbled, it reads the second batch
- // of addr misaligned by 3 bytes.
- if (IsIPv6() && memcmp(ip, pchIPv4+3, sizeof(pchIPv4)-3) == 0)
- return false;
-
// unspecified IPv6 address (::/128)
unsigned char ipNone6[16] = {};
- if (IsIPv6() && memcmp(ip, ipNone6, 16) == 0)
+ if (IsIPv6() && memcmp(m_addr.data(), ipNone6, sizeof(ipNone6)) == 0) {
return false;
+ }
// documentation IPv6 address
if (IsRFC3849())
@@ -287,17 +283,11 @@ bool CNetAddr::IsValid() const
if (IsInternal())
return false;
- if (IsIPv4())
- {
- // INADDR_NONE
- uint32_t ipNone = INADDR_NONE;
- if (memcmp(ip+12, &ipNone, 4) == 0)
- return false;
-
- // 0
- ipNone = 0;
- if (memcmp(ip+12, &ipNone, 4) == 0)
+ if (IsIPv4()) {
+ const uint32_t addr = ReadBE32(m_addr.data());
+ if (addr == INADDR_ANY || addr == INADDR_NONE) {
return false;
+ }
}
return true;
@@ -318,7 +308,7 @@ bool CNetAddr::IsRoutable() const
}
/**
- * @returns Whether or not this is a dummy address that maps a name into IPv6.
+ * @returns Whether or not this is a dummy address that represents a name.
*
* @see CNetAddr::SetInternal(const std::string &)
*/
@@ -341,9 +331,9 @@ enum Network CNetAddr::GetNetwork() const
std::string CNetAddr::ToStringIP() const
{
if (IsTor())
- return EncodeBase32(&ip[6], 10) + ".onion";
+ return EncodeBase32(m_addr) + ".onion";
if (IsInternal())
- return EncodeBase32(ip + sizeof(g_internal_prefix), sizeof(ip) - sizeof(g_internal_prefix)) + ".internal";
+ return EncodeBase32(m_addr) + ".internal";
CService serv(*this, 0);
struct sockaddr_storage sockaddr;
socklen_t socklen = sizeof(sockaddr);
@@ -353,13 +343,13 @@ std::string CNetAddr::ToStringIP() const
return std::string(name);
}
if (IsIPv4())
- return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0));
- else
- return strprintf("%x:%x:%x:%x:%x:%x:%x:%x",
- GetByte(15) << 8 | GetByte(14), GetByte(13) << 8 | GetByte(12),
- GetByte(11) << 8 | GetByte(10), GetByte(9) << 8 | GetByte(8),
- GetByte(7) << 8 | GetByte(6), GetByte(5) << 8 | GetByte(4),
- GetByte(3) << 8 | GetByte(2), GetByte(1) << 8 | GetByte(0));
+ return strprintf("%u.%u.%u.%u", m_addr[0], m_addr[1], m_addr[2], m_addr[3]);
+ assert(IsIPv6());
+ return strprintf("%x:%x:%x:%x:%x:%x:%x:%x",
+ m_addr[0] << 8 | m_addr[1], m_addr[2] << 8 | m_addr[3],
+ m_addr[4] << 8 | m_addr[5], m_addr[6] << 8 | m_addr[7],
+ m_addr[8] << 8 | m_addr[9], m_addr[10] << 8 | m_addr[11],
+ m_addr[12] << 8 | m_addr[13], m_addr[14] << 8 | m_addr[15]);
}
std::string CNetAddr::ToString() const
@@ -369,12 +359,12 @@ std::string CNetAddr::ToString() const
bool operator==(const CNetAddr& a, const CNetAddr& b)
{
- return a.m_net == b.m_net && memcmp(a.ip, b.ip, 16) == 0;
+ return a.m_net == b.m_net && a.m_addr == b.m_addr;
}
bool operator<(const CNetAddr& a, const CNetAddr& b)
{
- return a.m_net < b.m_net || (a.m_net == b.m_net && memcmp(a.ip, b.ip, 16) < 0);
+ return std::tie(a.m_net, a.m_addr) < std::tie(b.m_net, b.m_addr);
}
/**
@@ -391,7 +381,8 @@ bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const
{
if (!IsIPv4())
return false;
- memcpy(pipv4Addr, ip+12, 4);
+ assert(sizeof(*pipv4Addr) == m_addr.size());
+ memcpy(pipv4Addr, m_addr.data(), m_addr.size());
return true;
}
@@ -410,7 +401,8 @@ bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
if (!IsIPv6()) {
return false;
}
- memcpy(pipv6Addr, ip, 16);
+ assert(sizeof(*pipv6Addr) == m_addr.size());
+ memcpy(pipv6Addr, m_addr.data(), m_addr.size());
return true;
}
@@ -421,15 +413,17 @@ bool CNetAddr::HasLinkedIPv4() const
uint32_t CNetAddr::GetLinkedIPv4() const
{
- if (IsIPv4() || IsRFC6145() || IsRFC6052()) {
- // IPv4, mapped IPv4, SIIT translated IPv4: the IPv4 address is the last 4 bytes of the address
- return ReadBE32(ip + 12);
+ if (IsIPv4()) {
+ return ReadBE32(m_addr.data());
+ } else if (IsRFC6052() || IsRFC6145()) {
+ // mapped IPv4, SIIT translated IPv4: the IPv4 address is the last 4 bytes of the address
+ return ReadBE32(MakeSpan(m_addr).last(ADDR_IPV4_SIZE).data());
} else if (IsRFC3964()) {
// 6to4 tunneled IPv4: the IPv4 address is in bytes 2-6
- return ReadBE32(ip + 2);
+ return ReadBE32(MakeSpan(m_addr).subspan(2, ADDR_IPV4_SIZE).data());
} else if (IsRFC4380()) {
// Teredo tunneled IPv4: the IPv4 address is in the last 4 bytes of the address, but bitflipped
- return ~ReadBE32(ip + 12);
+ return ~ReadBE32(MakeSpan(m_addr).last(ADDR_IPV4_SIZE).data());
}
assert(false);
}
@@ -458,10 +452,10 @@ uint32_t CNetAddr::GetMappedAS(const std::vector<bool> &asmap) const {
}
std::vector<bool> ip_bits(128);
if (HasLinkedIPv4()) {
- // For lookup, treat as if it was just an IPv4 address (pchIPv4 prefix + IPv4 bits)
+ // For lookup, treat as if it was just an IPv4 address (IPV4_IN_IPV6_PREFIX + IPv4 bits)
for (int8_t byte_i = 0; byte_i < 12; ++byte_i) {
for (uint8_t bit_i = 0; bit_i < 8; ++bit_i) {
- ip_bits[byte_i * 8 + bit_i] = (pchIPv4[byte_i] >> (7 - bit_i)) & 1;
+ ip_bits[byte_i * 8 + bit_i] = (IPV4_IN_IPV6_PREFIX[byte_i] >> (7 - bit_i)) & 1;
}
}
uint32_t ipv4 = GetLinkedIPv4();
@@ -470,8 +464,9 @@ uint32_t CNetAddr::GetMappedAS(const std::vector<bool> &asmap) const {
}
} else {
// Use all 128 bits of the IPv6 address otherwise
+ assert(IsIPv6());
for (int8_t byte_i = 0; byte_i < 16; ++byte_i) {
- uint8_t cur_byte = GetByte(15 - byte_i);
+ uint8_t cur_byte = m_addr[byte_i];
for (uint8_t bit_i = 0; bit_i < 8; ++bit_i) {
ip_bits[byte_i * 8 + bit_i] = (cur_byte >> (7 - bit_i)) & 1;
}
@@ -507,19 +502,15 @@ std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) co
}
vchRet.push_back(net_class);
- int nStartByte = 0;
- int nBits = 16;
+ int nBits{0};
if (IsLocal()) {
// all local addresses belong to the same group
- nBits = 0;
} else if (IsInternal()) {
// all internal-usage addresses get their own group
- nStartByte = sizeof(g_internal_prefix);
- nBits = (sizeof(ip) - sizeof(g_internal_prefix)) * 8;
+ nBits = ADDR_INTERNAL_SIZE * 8;
} else if (!IsRoutable()) {
// all other unroutable addresses belong to the same group
- nBits = 0;
} else if (HasLinkedIPv4()) {
// IPv4 addresses (and mapped IPv4 addresses) use /16 groups
uint32_t ipv4 = GetLinkedIPv4();
@@ -527,7 +518,6 @@ std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) co
vchRet.push_back((ipv4 >> 16) & 0xFF);
return vchRet;
} else if (IsTor()) {
- nStartByte = 6;
nBits = 4;
} else if (IsHeNet()) {
// for he.net, use /36 groups
@@ -537,23 +527,29 @@ std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) co
nBits = 32;
}
- // push our ip onto vchRet byte by byte...
- while (nBits >= 8)
- {
- vchRet.push_back(GetByte(15 - nStartByte));
- nStartByte++;
- nBits -= 8;
- }
+ // Push our address onto vchRet.
+ const size_t num_bytes = nBits / 8;
+ vchRet.insert(vchRet.end(), m_addr.begin(), m_addr.begin() + num_bytes);
+ nBits %= 8;
// ...for the last byte, push nBits and for the rest of the byte push 1's
- if (nBits > 0)
- vchRet.push_back(GetByte(15 - nStartByte) | ((1 << (8 - nBits)) - 1));
+ if (nBits > 0) {
+ assert(num_bytes < m_addr.size());
+ vchRet.push_back(m_addr[num_bytes] | ((1 << (8 - nBits)) - 1));
+ }
return vchRet;
}
+std::vector<unsigned char> CNetAddr::GetAddrBytes() const
+{
+ uint8_t serialized[V1_SERIALIZATION_SIZE];
+ SerializeV1Array(serialized);
+ return {std::begin(serialized), std::end(serialized)};
+}
+
uint64_t CNetAddr::GetHash() const
{
- uint256 hash = Hash(ip);
+ uint256 hash = Hash(m_addr);
uint64_t nRet;
memcpy(&nRet, &hash, sizeof(nRet));
return nRet;
@@ -764,53 +760,89 @@ CSubNet::CSubNet():
memset(netmask, 0, sizeof(netmask));
}
-CSubNet::CSubNet(const CNetAddr &addr, int32_t mask)
+CSubNet::CSubNet(const CNetAddr& addr, uint8_t mask) : CSubNet()
{
- valid = true;
+ valid = (addr.IsIPv4() && mask <= ADDR_IPV4_SIZE * 8) ||
+ (addr.IsIPv6() && mask <= ADDR_IPV6_SIZE * 8);
+ if (!valid) {
+ return;
+ }
+
+ assert(mask <= sizeof(netmask) * 8);
+
network = addr;
- // Default to /32 (IPv4) or /128 (IPv6), i.e. match single address
- memset(netmask, 255, sizeof(netmask));
-
- // IPv4 addresses start at offset 12, and first 12 bytes must match, so just offset n
- const int astartofs = network.IsIPv4() ? 12 : 0;
-
- int32_t n = mask;
- if(n >= 0 && n <= (128 - astartofs*8)) // Only valid if in range of bits of address
- {
- n += astartofs*8;
- // Clear bits [n..127]
- for (; n < 128; ++n)
- netmask[n>>3] &= ~(1<<(7-(n&7)));
- } else
- valid = false;
- // Normalize network according to netmask
- for(int x=0; x<16; ++x)
- network.ip[x] &= netmask[x];
+ uint8_t n = mask;
+ for (size_t i = 0; i < network.m_addr.size(); ++i) {
+ const uint8_t bits = n < 8 ? n : 8;
+ netmask[i] = (uint8_t)((uint8_t)0xFF << (8 - bits)); // Set first bits.
+ network.m_addr[i] &= netmask[i]; // Normalize network according to netmask.
+ n -= bits;
+ }
+}
+
+/**
+ * @returns The number of 1-bits in the prefix of the specified subnet mask. If
+ * the specified subnet mask is not a valid one, -1.
+ */
+static inline int NetmaskBits(uint8_t x)
+{
+ switch(x) {
+ 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;
+ }
}
-CSubNet::CSubNet(const CNetAddr &addr, const CNetAddr &mask)
+CSubNet::CSubNet(const CNetAddr& addr, const CNetAddr& mask) : CSubNet()
{
- valid = true;
- network = addr;
- // Default to /32 (IPv4) or /128 (IPv6), i.e. match single address
- memset(netmask, 255, sizeof(netmask));
+ valid = (addr.IsIPv4() || addr.IsIPv6()) && addr.m_net == mask.m_net;
+ if (!valid) {
+ return;
+ }
+ // Check if `mask` contains 1-bits after 0-bits (which is an invalid netmask).
+ bool zeros_found = false;
+ for (auto b : mask.m_addr) {
+ const int num_bits = NetmaskBits(b);
+ if (num_bits == -1 || (zeros_found && num_bits != 0)) {
+ valid = false;
+ return;
+ }
+ if (num_bits < 8) {
+ zeros_found = true;
+ }
+ }
+
+ assert(mask.m_addr.size() <= sizeof(netmask));
- // IPv4 addresses start at offset 12, and first 12 bytes must match, so just offset n
- const int astartofs = network.IsIPv4() ? 12 : 0;
+ memcpy(netmask, mask.m_addr.data(), mask.m_addr.size());
- for(int x=astartofs; x<16; ++x)
- netmask[x] = mask.ip[x];
+ network = addr;
// Normalize network according to netmask
- for(int x=0; x<16; ++x)
- network.ip[x] &= netmask[x];
+ for (size_t x = 0; x < network.m_addr.size(); ++x) {
+ network.m_addr[x] &= netmask[x];
+ }
}
-CSubNet::CSubNet(const CNetAddr &addr):
- valid(addr.IsValid())
+CSubNet::CSubNet(const CNetAddr& addr) : CSubNet()
{
- memset(netmask, 255, sizeof(netmask));
+ valid = addr.IsIPv4() || addr.IsIPv6();
+ if (!valid) {
+ return;
+ }
+
+ assert(addr.m_addr.size() <= sizeof(netmask));
+
+ memset(netmask, 0xFF, addr.m_addr.size());
+
network = addr;
}
@@ -822,68 +854,29 @@ bool CSubNet::Match(const CNetAddr &addr) const
{
if (!valid || !addr.IsValid() || network.m_net != addr.m_net)
return false;
- for(int x=0; x<16; ++x)
- if ((addr.ip[x] & netmask[x]) != network.ip[x])
+ assert(network.m_addr.size() == addr.m_addr.size());
+ for (size_t x = 0; x < addr.m_addr.size(); ++x) {
+ if ((addr.m_addr[x] & netmask[x]) != network.m_addr[x]) {
return false;
- return true;
-}
-
-/**
- * @returns The number of 1-bits in the prefix of the specified subnet mask. If
- * the specified subnet mask is not a valid one, -1.
- */
-static inline int NetmaskBits(uint8_t x)
-{
- switch(x) {
- 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;
+ }
}
+ return true;
}
std::string CSubNet::ToString() const
{
- /* Parse binary 1{n}0{N-n} to see if mask can be represented as /n */
- int cidr = 0;
- bool valid_cidr = true;
- int n = network.IsIPv4() ? 12 : 0;
- for (; n < 16 && netmask[n] == 0xff; ++n)
- cidr += 8;
- if (n < 16) {
- int bits = NetmaskBits(netmask[n]);
- if (bits < 0)
- valid_cidr = false;
- else
- cidr += bits;
- ++n;
- }
- for (; n < 16 && valid_cidr; ++n)
- if (netmask[n] != 0x00)
- valid_cidr = false;
-
- /* Format output */
- std::string strNetmask;
- if (valid_cidr) {
- strNetmask = strprintf("%u", cidr);
- } else {
- if (network.IsIPv4())
- strNetmask = strprintf("%u.%u.%u.%u", netmask[12], netmask[13], netmask[14], netmask[15]);
- else
- strNetmask = strprintf("%x:%x:%x:%x:%x:%x:%x:%x",
- netmask[0] << 8 | netmask[1], netmask[2] << 8 | netmask[3],
- netmask[4] << 8 | netmask[5], netmask[6] << 8 | netmask[7],
- netmask[8] << 8 | netmask[9], netmask[10] << 8 | netmask[11],
- netmask[12] << 8 | netmask[13], netmask[14] << 8 | netmask[15]);
+ assert(network.m_addr.size() <= sizeof(netmask));
+
+ uint8_t cidr = 0;
+
+ for (size_t i = 0; i < network.m_addr.size(); ++i) {
+ if (netmask[i] == 0x00) {
+ break;
+ }
+ cidr += NetmaskBits(netmask[i]);
}
- return network.ToString() + "/" + strNetmask;
+ return network.ToString() + strprintf("/%u", cidr);
}
bool CSubNet::IsValid() const
diff --git a/src/netaddress.h b/src/netaddress.h
index 0365907d44..d00f5a6f55 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -9,9 +9,12 @@
#include <config/bitcoin-config.h>
#endif
+#include <attributes.h>
#include <compat.h>
+#include <prevector.h>
#include <serialize.h>
+#include <array>
#include <cstdint>
#include <string>
#include <vector>
@@ -39,16 +42,49 @@ enum Network
/// TORv2
NET_ONION,
- /// A set of dummy addresses that map a name to an IPv6 address. These
- /// addresses belong to RFC4193's fc00::/7 subnet (unique-local addresses).
- /// We use them to map a string or FQDN to an IPv6 address in CAddrMan to
- /// keep track of which DNS seeds were used.
+ /// A set of addresses that represent the hash of a string or FQDN. We use
+ /// them in CAddrMan to keep track of which DNS seeds were used.
NET_INTERNAL,
/// Dummy value to indicate the number of NET_* constants.
NET_MAX,
};
+/// Prefix of an IPv6 address when it contains an embedded IPv4 address.
+/// Used when (un)serializing addresses in ADDRv1 format (pre-BIP155).
+static const std::array<uint8_t, 12> IPV4_IN_IPV6_PREFIX{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF
+};
+
+/// Prefix of an IPv6 address when it contains an embedded TORv2 address.
+/// Used when (un)serializing addresses in ADDRv1 format (pre-BIP155).
+/// Such dummy IPv6 addresses are guaranteed to not be publicly routable as they
+/// fall under RFC4193's fc00::/7 subnet allocated to unique-local addresses.
+static const std::array<uint8_t, 6> TORV2_IN_IPV6_PREFIX{
+ 0xFD, 0x87, 0xD8, 0x7E, 0xEB, 0x43
+};
+
+/// Prefix of an IPv6 address when it contains an embedded "internal" address.
+/// Used when (un)serializing addresses in ADDRv1 format (pre-BIP155).
+/// The prefix comes from 0xFD + SHA256("bitcoin")[0:5].
+/// Such dummy IPv6 addresses are guaranteed to not be publicly routable as they
+/// fall under RFC4193's fc00::/7 subnet allocated to unique-local addresses.
+static const std::array<uint8_t, 6> INTERNAL_IN_IPV6_PREFIX{
+ 0xFD, 0x6B, 0x88, 0xC0, 0x87, 0x24 // 0xFD + sha256("bitcoin")[0:5].
+};
+
+/// Size of IPv4 address (in bytes).
+static constexpr size_t ADDR_IPV4_SIZE = 4;
+
+/// Size of IPv6 address (in bytes).
+static constexpr size_t ADDR_IPV6_SIZE = 16;
+
+/// Size of TORv2 address (in bytes).
+static constexpr size_t ADDR_TORV2_SIZE = 10;
+
+/// Size of "internal" (NET_INTERNAL) address (in bytes).
+static constexpr size_t ADDR_INTERNAL_SIZE = 10;
+
/**
* Network address.
*/
@@ -56,11 +92,16 @@ class CNetAddr
{
protected:
/**
+ * Raw representation of the network address.
+ * In network byte order (big endian) for IPv4 and IPv6.
+ */
+ prevector<ADDR_IPV6_SIZE, uint8_t> m_addr{ADDR_IPV6_SIZE, 0x0};
+
+ /**
* Network to which this address belongs.
*/
Network m_net{NET_IPV6};
- unsigned char ip[16]; // in network byte order
uint32_t scopeId{0}; // for scoped/link-local ipv6 addresses
public:
@@ -74,13 +115,7 @@ class CNetAddr
* (e.g. IPv4) disguised as IPv6. This encoding is used in the legacy
* `addr` encoding.
*/
- void SetLegacyIPv6(const uint8_t ipv6[16]);
-
- /**
- * 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);
+ void SetLegacyIPv6(Span<const uint8_t> ipv6);
bool SetInternal(const std::string& name);
@@ -111,7 +146,6 @@ class CNetAddr
enum Network GetNetwork() const;
std::string ToString() const;
std::string ToStringIP() const;
- unsigned int GetByte(int n) const;
uint64_t GetHash() const;
bool GetInAddr(struct in_addr* pipv4Addr) const;
uint32_t GetNetClass() const;
@@ -127,7 +161,7 @@ class CNetAddr
uint32_t GetMappedAS(const std::vector<bool> &asmap) const;
std::vector<unsigned char> GetGroup(const std::vector<bool> &asmap) const;
- std::vector<unsigned char> GetAddrBytes() const { return {std::begin(ip), std::end(ip)}; }
+ std::vector<unsigned char> GetAddrBytes() const;
int GetReachabilityFrom(const CNetAddr *paddrPartner = nullptr) const;
explicit CNetAddr(const struct in6_addr& pipv6Addr, const uint32_t scope = 0);
@@ -143,7 +177,7 @@ class CNetAddr
template <typename Stream>
void Serialize(Stream& s) const
{
- s << ip;
+ SerializeV1Stream(s);
}
/**
@@ -152,14 +186,92 @@ class CNetAddr
template <typename Stream>
void Unserialize(Stream& s)
{
- unsigned char ip_temp[sizeof(ip)];
- s >> ip_temp;
+ UnserializeV1Stream(s);
+ }
+
+ friend class CSubNet;
+
+ private:
+ /**
+ * Size of CNetAddr when serialized as ADDRv1 (pre-BIP155) (in bytes).
+ */
+ static constexpr size_t V1_SERIALIZATION_SIZE = ADDR_IPV6_SIZE;
+
+ /**
+ * Serialize in pre-ADDRv2/BIP155 format to an array.
+ * Some addresses (e.g. TORv3) cannot be serialized in pre-BIP155 format.
+ */
+ void SerializeV1Array(uint8_t (&arr)[V1_SERIALIZATION_SIZE]) const
+ {
+ size_t prefix_size;
+
+ switch (m_net) {
+ case NET_IPV6:
+ assert(m_addr.size() == sizeof(arr));
+ memcpy(arr, m_addr.data(), m_addr.size());
+ return;
+ case NET_IPV4:
+ prefix_size = sizeof(IPV4_IN_IPV6_PREFIX);
+ assert(prefix_size + m_addr.size() == sizeof(arr));
+ memcpy(arr, IPV4_IN_IPV6_PREFIX.data(), prefix_size);
+ memcpy(arr + prefix_size, m_addr.data(), m_addr.size());
+ return;
+ case NET_ONION:
+ prefix_size = sizeof(TORV2_IN_IPV6_PREFIX);
+ assert(prefix_size + m_addr.size() == sizeof(arr));
+ memcpy(arr, TORV2_IN_IPV6_PREFIX.data(), prefix_size);
+ memcpy(arr + prefix_size, m_addr.data(), m_addr.size());
+ return;
+ case NET_INTERNAL:
+ prefix_size = sizeof(INTERNAL_IN_IPV6_PREFIX);
+ assert(prefix_size + m_addr.size() == sizeof(arr));
+ memcpy(arr, INTERNAL_IN_IPV6_PREFIX.data(), prefix_size);
+ memcpy(arr + prefix_size, m_addr.data(), m_addr.size());
+ return;
+ case NET_UNROUTABLE:
+ case NET_MAX:
+ assert(false);
+ } // no default case, so the compiler can warn about missing cases
+
+ assert(false);
+ }
+
+ /**
+ * Serialize in pre-ADDRv2/BIP155 format to a stream.
+ * Some addresses (e.g. TORv3) cannot be serialized in pre-BIP155 format.
+ */
+ template <typename Stream>
+ void SerializeV1Stream(Stream& s) const
+ {
+ uint8_t serialized[V1_SERIALIZATION_SIZE];
+
+ SerializeV1Array(serialized);
+
+ s << serialized;
+ }
+
+ /**
+ * Unserialize from a pre-ADDRv2/BIP155 format from an array.
+ */
+ void UnserializeV1Array(uint8_t (&arr)[V1_SERIALIZATION_SIZE])
+ {
// Use SetLegacyIPv6() so that m_net is set correctly. For example
// ::FFFF:0102:0304 should be set as m_net=NET_IPV4 (1.2.3.4).
- SetLegacyIPv6(ip_temp);
+ SetLegacyIPv6(arr);
}
- friend class CSubNet;
+ /**
+ * Unserialize from a pre-ADDRv2/BIP155 format from a stream.
+ */
+ template <typename Stream>
+ void UnserializeV1Stream(Stream& s)
+ {
+ uint8_t serialized[V1_SERIALIZATION_SIZE];
+
+ s >> serialized;
+
+ UnserializeV1Array(serialized);
+ }
};
class CSubNet
@@ -174,11 +286,11 @@ class CSubNet
public:
CSubNet();
- CSubNet(const CNetAddr &addr, int32_t mask);
- CSubNet(const CNetAddr &addr, const CNetAddr &mask);
+ CSubNet(const CNetAddr& addr, uint8_t mask);
+ CSubNet(const CNetAddr& addr, const CNetAddr& mask);
//constructor for single ip subnet (<ipv4>/32 or <ipv6>/128)
- explicit CSubNet(const CNetAddr &addr);
+ explicit CSubNet(const CNetAddr& addr);
bool Match(const CNetAddr &addr) const;
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 3a3b5f3e66..0273839017 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -13,6 +13,7 @@
#include <atomic>
#include <cstdint>
+#include <limits>
#ifndef WIN32
#include <fcntl.h>
@@ -838,8 +839,8 @@ bool LookupSubNet(const std::string& strSubnet, CSubNet& ret)
if (slash != strSubnet.npos)
{
std::string strNetmask = strSubnet.substr(slash + 1);
- int32_t n;
- if (ParseInt32(strNetmask, &n)) {
+ uint8_t n;
+ if (ParseUInt8(strNetmask, &n)) {
// If valid number, assume CIDR variable-length subnet masking
ret = CSubNet(network, n);
return ret.IsValid();
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index f53fcc41f3..c290ad1316 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -27,9 +27,11 @@
#include <qt/walletmodel.h>
#endif // ENABLE_WALLET
+#include <init.h>
#include <interfaces/handler.h>
#include <interfaces/node.h>
#include <node/context.h>
+#include <node/ui_interface.h>
#include <noui.h>
#include <uint256.h>
#include <util/system.h>
@@ -37,6 +39,7 @@
#include <util/translation.h>
#include <validation.h>
+#include <boost/signals2/connection.hpp>
#include <memory>
#include <QApplication>
@@ -193,10 +196,9 @@ void BitcoinCore::shutdown()
static int qt_argc = 1;
static const char* qt_argv = "bitcoin-qt";
-BitcoinApplication::BitcoinApplication(interfaces::Node& node):
+BitcoinApplication::BitcoinApplication():
QApplication(qt_argc, const_cast<char **>(&qt_argv)),
coreThread(nullptr),
- m_node(node),
optionsModel(nullptr),
clientModel(nullptr),
window(nullptr),
@@ -204,6 +206,7 @@ BitcoinApplication::BitcoinApplication(interfaces::Node& node):
returnValue(0),
platformStyle(nullptr)
{
+ // Qt runs setlocale(LC_ALL, "") on initialization.
RegisterMetaTypes();
setQuitOnLastWindowClosed(false);
}
@@ -246,12 +249,12 @@ void BitcoinApplication::createPaymentServer()
void BitcoinApplication::createOptionsModel(bool resetSettings)
{
- optionsModel = new OptionsModel(m_node, this, resetSettings);
+ optionsModel = new OptionsModel(this, resetSettings);
}
void BitcoinApplication::createWindow(const NetworkStyle *networkStyle)
{
- window = new BitcoinGUI(m_node, platformStyle, networkStyle, nullptr);
+ window = new BitcoinGUI(node(), platformStyle, networkStyle, nullptr);
pollShutdownTimer = new QTimer(window);
connect(pollShutdownTimer, &QTimer::timeout, window, &BitcoinGUI::detectShutdown);
@@ -259,17 +262,26 @@ void BitcoinApplication::createWindow(const NetworkStyle *networkStyle)
void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle)
{
- SplashScreen *splash = new SplashScreen(m_node, nullptr, networkStyle);
+ assert(!m_splash);
+ m_splash = new SplashScreen(nullptr, networkStyle);
// We don't hold a direct pointer to the splash screen after creation, but the splash
// screen will take care of deleting itself when finish() happens.
- splash->show();
- connect(this, &BitcoinApplication::splashFinished, splash, &SplashScreen::finish);
- connect(this, &BitcoinApplication::requestedShutdown, splash, &QWidget::close);
+ m_splash->show();
+ connect(this, &BitcoinApplication::splashFinished, m_splash, &SplashScreen::finish);
+ connect(this, &BitcoinApplication::requestedShutdown, m_splash, &QWidget::close);
+}
+
+void BitcoinApplication::setNode(interfaces::Node& node)
+{
+ assert(!m_node);
+ m_node = &node;
+ if (optionsModel) optionsModel->setNode(*m_node);
+ if (m_splash) m_splash->setNode(*m_node);
}
bool BitcoinApplication::baseInitialize()
{
- return m_node.baseInitialize();
+ return node().baseInitialize();
}
void BitcoinApplication::startThread()
@@ -277,7 +289,7 @@ void BitcoinApplication::startThread()
if(coreThread)
return;
coreThread = new QThread(this);
- BitcoinCore *executor = new BitcoinCore(m_node);
+ BitcoinCore *executor = new BitcoinCore(node());
executor->moveToThread(coreThread);
/* communication to and from thread */
@@ -298,8 +310,8 @@ void BitcoinApplication::parameterSetup()
// print to the console unnecessarily.
gArgs.SoftSetBoolArg("-printtoconsole", false);
- m_node.initLogging();
- m_node.initParameterInteraction();
+ InitLogging(gArgs);
+ InitParameterInteraction(gArgs);
}
void BitcoinApplication::InitializePruneSetting(bool prune)
@@ -331,7 +343,7 @@ void BitcoinApplication::requestShutdown()
window->unsubscribeFromCoreSignals();
// Request node shutdown, which can interrupt long operations, like
// rescanning a wallet.
- m_node.startShutdown();
+ node().startShutdown();
// Unsetting the client model can cause the current thread to wait for node
// to complete an operation, like wait for a RPC execution to complete.
window->setClientModel(nullptr);
@@ -353,7 +365,7 @@ void BitcoinApplication::initializeResult(bool success, interfaces::BlockAndHead
{
// Log this only after AppInitMain finishes, as then logging setup is guaranteed complete
qInfo() << "Platform customization:" << platformStyle->getName();
- clientModel = new ClientModel(m_node, optionsModel);
+ clientModel = new ClientModel(node(), optionsModel);
window->setClientModel(clientModel, &tip_info);
#ifdef ENABLE_WALLET
if (WalletModel::isWalletEnabled()) {
@@ -437,9 +449,9 @@ int GuiMain(int argc, char* argv[])
std::unique_ptr<interfaces::Node> node = interfaces::MakeNode(&node_context);
// Subscribe to global signals from core
- std::unique_ptr<interfaces::Handler> handler_message_box = node->handleMessageBox(noui_ThreadSafeMessageBox);
- std::unique_ptr<interfaces::Handler> handler_question = node->handleQuestion(noui_ThreadSafeQuestion);
- std::unique_ptr<interfaces::Handler> handler_init_message = node->handleInitMessage(noui_InitMessage);
+ boost::signals2::scoped_connection handler_message_box = ::uiInterface.ThreadSafeMessageBox_connect(noui_ThreadSafeMessageBox);
+ boost::signals2::scoped_connection handler_question = ::uiInterface.ThreadSafeQuestion_connect(noui_ThreadSafeQuestion);
+ boost::signals2::scoped_connection handler_init_message = ::uiInterface.InitMessage_connect(noui_InitMessage);
// Do not refer to data directory yet, this can be overridden by Intro::pickDataDirectory
@@ -453,15 +465,15 @@ int GuiMain(int argc, char* argv[])
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
- BitcoinApplication app(*node);
+ BitcoinApplication app;
/// 2. Parse command-line options. We do this after qt in order to show an error if there are problems parsing these
// Command-line options take precedence:
- node->setupServerArgs();
+ SetupServerArgs(node_context);
SetupUIArgs(gArgs);
std::string error;
- if (!node->parseParameters(argc, argv, error)) {
- node->initError(strprintf(Untranslated("Error parsing command line arguments: %s\n"), error));
+ if (!gArgs.ParseParameters(argc, argv, error)) {
+ InitError(strprintf(Untranslated("Error parsing command line arguments: %s\n"), error));
// Create a message box, because the gui has neither been created nor has subscribed to core signals
QMessageBox::critical(nullptr, PACKAGE_NAME,
// message can not be translated because translations have not been initialized
@@ -487,7 +499,7 @@ int GuiMain(int argc, char* argv[])
// Show help message immediately after parsing command-line options (for "-lang") and setting locale,
// but before showing splash screen.
if (HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
- HelpMessageDialog help(*node, nullptr, gArgs.IsArgSet("-version"));
+ HelpMessageDialog help(nullptr, gArgs.IsArgSet("-version"));
help.showOrPrint();
return EXIT_SUCCESS;
}
@@ -497,18 +509,18 @@ int GuiMain(int argc, char* argv[])
bool did_show_intro = false;
bool prune = false; // Intro dialog prune check box
// Gracefully exit if the user cancels
- if (!Intro::showIfNeeded(*node, did_show_intro, prune)) return EXIT_SUCCESS;
+ if (!Intro::showIfNeeded(did_show_intro, prune)) return EXIT_SUCCESS;
/// 6. Determine availability of data directory and parse bitcoin.conf
/// - Do not call GetDataDir(true) before this step finishes
if (!CheckDataDirOption()) {
- node->initError(strprintf(Untranslated("Specified data directory \"%s\" does not exist.\n"), gArgs.GetArg("-datadir", "")));
+ InitError(strprintf(Untranslated("Specified data directory \"%s\" does not exist.\n"), gArgs.GetArg("-datadir", "")));
QMessageBox::critical(nullptr, PACKAGE_NAME,
QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(gArgs.GetArg("-datadir", ""))));
return EXIT_FAILURE;
}
- if (!node->readConfigFiles(error)) {
- node->initError(strprintf(Untranslated("Error reading configuration file: %s\n"), error));
+ if (!gArgs.ReadConfigFiles(error, true)) {
+ InitError(strprintf(Untranslated("Error reading configuration file: %s\n"), error));
QMessageBox::critical(nullptr, PACKAGE_NAME,
QObject::tr("Error: Cannot parse configuration file: %1.").arg(QString::fromStdString(error)));
return EXIT_FAILURE;
@@ -522,18 +534,18 @@ int GuiMain(int argc, char* argv[])
// Check for -chain, -testnet or -regtest parameter (Params() calls are only valid after this clause)
try {
- node->selectParams(gArgs.GetChainName());
+ SelectParams(gArgs.GetChainName());
} catch(std::exception &e) {
- node->initError(Untranslated(strprintf("%s\n", e.what())));
+ InitError(Untranslated(strprintf("%s\n", e.what())));
QMessageBox::critical(nullptr, PACKAGE_NAME, QObject::tr("Error: %1").arg(e.what()));
return EXIT_FAILURE;
}
#ifdef ENABLE_WALLET
// Parse URIs on command line -- this can affect Params()
- PaymentServer::ipcParseCommandLine(*node, argc, argv);
+ PaymentServer::ipcParseCommandLine(argc, argv);
#endif
- if (!node->initSettings(error)) {
- node->initError(Untranslated(error));
+ if (!gArgs.InitSettings(error)) {
+ InitError(Untranslated(error));
QMessageBox::critical(nullptr, PACKAGE_NAME, QObject::tr("Error initializing settings: %1").arg(QString::fromStdString(error)));
return EXIT_FAILURE;
}
@@ -587,6 +599,8 @@ int GuiMain(int argc, char* argv[])
if (gArgs.GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) && !gArgs.GetBoolArg("-min", false))
app.createSplashScreen(networkStyle.data());
+ app.setNode(*node);
+
int rv = EXIT_SUCCESS;
try
{
@@ -609,10 +623,10 @@ int GuiMain(int argc, char* argv[])
}
} catch (const std::exception& e) {
PrintExceptionContinue(&e, "Runaway exception");
- app.handleRunawayException(QString::fromStdString(node->getWarnings().translated));
+ app.handleRunawayException(QString::fromStdString(app.node().getWarnings().translated));
} catch (...) {
PrintExceptionContinue(nullptr, "Runaway exception");
- app.handleRunawayException(QString::fromStdString(node->getWarnings().translated));
+ app.handleRunawayException(QString::fromStdString(app.node().getWarnings().translated));
}
return rv;
}
diff --git a/src/qt/bitcoin.h b/src/qt/bitcoin.h
index 20c6dfc047..69e0a5921e 100644
--- a/src/qt/bitcoin.h
+++ b/src/qt/bitcoin.h
@@ -10,6 +10,7 @@
#endif
#include <QApplication>
+#include <assert.h>
#include <memory>
#include <interfaces/node.h>
@@ -20,6 +21,7 @@ class NetworkStyle;
class OptionsModel;
class PaymentServer;
class PlatformStyle;
+class SplashScreen;
class WalletController;
class WalletModel;
@@ -54,7 +56,7 @@ class BitcoinApplication: public QApplication
{
Q_OBJECT
public:
- explicit BitcoinApplication(interfaces::Node& node);
+ explicit BitcoinApplication();
~BitcoinApplication();
#ifdef ENABLE_WALLET
@@ -88,6 +90,9 @@ public:
/// Setup platform style
void setupPlatformStyle();
+ interfaces::Node& node() const { assert(m_node); return *m_node; }
+ void setNode(interfaces::Node& node);
+
public Q_SLOTS:
void initializeResult(bool success, interfaces::BlockAndHeaderTipInfo tip_info);
void shutdownResult();
@@ -102,7 +107,6 @@ Q_SIGNALS:
private:
QThread *coreThread;
- interfaces::Node& m_node;
OptionsModel *optionsModel;
ClientModel *clientModel;
BitcoinGUI *window;
@@ -114,6 +118,8 @@ private:
int returnValue;
const PlatformStyle *platformStyle;
std::unique_ptr<QWidget> shutdownWindow;
+ SplashScreen* m_splash = nullptr;
+ interfaces::Node* m_node = nullptr;
void startThread();
};
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 56adbf249a..8935ff19bf 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -95,7 +95,7 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty
updateWindowTitle();
rpcConsole = new RPCConsole(node, _platformStyle, nullptr);
- helpMessageDialog = new HelpMessageDialog(node, this, false);
+ helpMessageDialog = new HelpMessageDialog(this, false);
#ifdef ENABLE_WALLET
if(enableWallet)
{
@@ -821,7 +821,7 @@ void BitcoinGUI::aboutClicked()
if(!clientModel)
return;
- HelpMessageDialog dlg(m_node, this, true);
+ HelpMessageDialog dlg(this, true);
dlg.exec();
}
diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui
index 93840b4169..d210faec03 100644
--- a/src/qt/forms/debugwindow.ui
+++ b/src/qt/forms/debugwindow.ui
@@ -290,7 +290,7 @@
<item row="11" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
- <string>Current number of blocks</string>
+ <string>Current block height</string>
</property>
</widget>
</item>
diff --git a/src/qt/forms/receivecoinsdialog.ui b/src/qt/forms/receivecoinsdialog.ui
index 7dbee6d689..06d39426c9 100644
--- a/src/qt/forms/receivecoinsdialog.ui
+++ b/src/qt/forms/receivecoinsdialog.ui
@@ -114,6 +114,12 @@
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/receiving_addresses</normaloff>:/icons/receiving_addresses</iconset>
</property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
</widget>
</item>
<item>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 6e34aca0eb..bab17562a6 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -21,11 +21,6 @@
#include <util/system.h>
#ifdef WIN32
-#ifdef _WIN32_IE
-#undef _WIN32_IE
-#endif
-#define _WIN32_IE 0x0501
-#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index ad21dfc3ef..235722d091 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -6,6 +6,7 @@
#include <config/bitcoin-config.h>
#endif
+#include <chainparams.h>
#include <fs.h>
#include <qt/intro.h>
#include <qt/forms/ui_intro.h>
@@ -181,7 +182,7 @@ void Intro::setDataDirectory(const QString &dataDir)
}
}
-bool Intro::showIfNeeded(interfaces::Node& node, bool& did_show_intro, bool& prune)
+bool Intro::showIfNeeded(bool& did_show_intro, bool& prune)
{
did_show_intro = false;
@@ -199,13 +200,13 @@ bool Intro::showIfNeeded(interfaces::Node& node, bool& did_show_intro, bool& pru
{
/* Use selectParams here to guarantee Params() can be used by node interface */
try {
- node.selectParams(gArgs.GetChainName());
+ SelectParams(gArgs.GetChainName());
} catch (const std::exception&) {
return false;
}
/* If current default data directory does not exist, let the user choose one */
- Intro intro(0, node.getAssumedBlockchainSize(), node.getAssumedChainStateSize());
+ Intro intro(0, Params().AssumedBlockchainSize(), Params().AssumedChainStateSize());
intro.setDataDirectory(dataDir);
intro.setWindowIcon(QIcon(":icons/bitcoin"));
did_show_intro = true;
@@ -242,7 +243,7 @@ bool Intro::showIfNeeded(interfaces::Node& node, bool& did_show_intro, bool& pru
* (to be consistent with bitcoind behavior)
*/
if(dataDir != GUIUtil::getDefaultDataDirectory()) {
- node.softSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); // use OS locale for path setting
+ gArgs.SoftSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); // use OS locale for path setting
}
return true;
}
diff --git a/src/qt/intro.h b/src/qt/intro.h
index 732393246e..51f42de7ac 100644
--- a/src/qt/intro.h
+++ b/src/qt/intro.h
@@ -47,7 +47,7 @@ public:
* @note do NOT call global GetDataDir() before calling this function, this
* will cause the wrong path to be cached.
*/
- static bool showIfNeeded(interfaces::Node& node, bool& did_show_intro, bool& prune);
+ static bool showIfNeeded(bool& did_show_intro, bool& prune);
Q_SIGNALS:
void requestCheck();
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index 58a7591c95..7e089b4f95 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -27,8 +27,8 @@ const char *DEFAULT_GUI_PROXY_HOST = "127.0.0.1";
static const QString GetDefaultProxyAddress();
-OptionsModel::OptionsModel(interfaces::Node& node, QObject *parent, bool resetSettings) :
- QAbstractListModel(parent), m_node(node)
+OptionsModel::OptionsModel(QObject *parent, bool resetSettings) :
+ QAbstractListModel(parent)
{
Init(resetSettings);
}
@@ -97,12 +97,12 @@ void OptionsModel::Init(bool resetSettings)
if (!settings.contains("nDatabaseCache"))
settings.setValue("nDatabaseCache", (qint64)nDefaultDbCache);
- if (!m_node.softSetArg("-dbcache", settings.value("nDatabaseCache").toString().toStdString()))
+ if (!gArgs.SoftSetArg("-dbcache", settings.value("nDatabaseCache").toString().toStdString()))
addOverriddenOption("-dbcache");
if (!settings.contains("nThreadsScriptVerif"))
settings.setValue("nThreadsScriptVerif", DEFAULT_SCRIPTCHECK_THREADS);
- if (!m_node.softSetArg("-par", settings.value("nThreadsScriptVerif").toString().toStdString()))
+ if (!gArgs.SoftSetArg("-par", settings.value("nThreadsScriptVerif").toString().toStdString()))
addOverriddenOption("-par");
if (!settings.contains("strDataDir"))
@@ -112,19 +112,19 @@ void OptionsModel::Init(bool resetSettings)
#ifdef ENABLE_WALLET
if (!settings.contains("bSpendZeroConfChange"))
settings.setValue("bSpendZeroConfChange", true);
- if (!m_node.softSetBoolArg("-spendzeroconfchange", settings.value("bSpendZeroConfChange").toBool()))
+ if (!gArgs.SoftSetBoolArg("-spendzeroconfchange", settings.value("bSpendZeroConfChange").toBool()))
addOverriddenOption("-spendzeroconfchange");
#endif
// Network
if (!settings.contains("fUseUPnP"))
settings.setValue("fUseUPnP", DEFAULT_UPNP);
- if (!m_node.softSetBoolArg("-upnp", settings.value("fUseUPnP").toBool()))
+ if (!gArgs.SoftSetBoolArg("-upnp", settings.value("fUseUPnP").toBool()))
addOverriddenOption("-upnp");
if (!settings.contains("fListen"))
settings.setValue("fListen", DEFAULT_LISTEN);
- if (!m_node.softSetBoolArg("-listen", settings.value("fListen").toBool()))
+ if (!gArgs.SoftSetBoolArg("-listen", settings.value("fListen").toBool()))
addOverriddenOption("-listen");
if (!settings.contains("fUseProxy"))
@@ -132,7 +132,7 @@ void OptionsModel::Init(bool resetSettings)
if (!settings.contains("addrProxy"))
settings.setValue("addrProxy", GetDefaultProxyAddress());
// Only try to set -proxy, if user has enabled fUseProxy
- if (settings.value("fUseProxy").toBool() && !m_node.softSetArg("-proxy", settings.value("addrProxy").toString().toStdString()))
+ if ((settings.value("fUseProxy").toBool() && !gArgs.SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString())))
addOverriddenOption("-proxy");
else if(!settings.value("fUseProxy").toBool() && !gArgs.GetArg("-proxy", "").empty())
addOverriddenOption("-proxy");
@@ -142,7 +142,7 @@ void OptionsModel::Init(bool resetSettings)
if (!settings.contains("addrSeparateProxyTor"))
settings.setValue("addrSeparateProxyTor", GetDefaultProxyAddress());
// Only try to set -onion, if user has enabled fUseSeparateProxyTor
- if (settings.value("fUseSeparateProxyTor").toBool() && !m_node.softSetArg("-onion", settings.value("addrSeparateProxyTor").toString().toStdString()))
+ if ((settings.value("fUseSeparateProxyTor").toBool() && !gArgs.SoftSetArg("-onion", settings.value("addrSeparateProxyTor").toString().toStdString())))
addOverriddenOption("-onion");
else if(!settings.value("fUseSeparateProxyTor").toBool() && !gArgs.GetArg("-onion", "").empty())
addOverriddenOption("-onion");
@@ -150,7 +150,7 @@ void OptionsModel::Init(bool resetSettings)
// Display
if (!settings.contains("language"))
settings.setValue("language", "");
- if (!m_node.softSetArg("-lang", settings.value("language").toString().toStdString()))
+ if (!gArgs.SoftSetArg("-lang", settings.value("language").toString().toStdString()))
addOverriddenOption("-lang");
language = settings.value("language").toString();
@@ -244,10 +244,10 @@ void OptionsModel::SetPruneEnabled(bool prune, bool force)
const int64_t prune_target_mib = PruneGBtoMiB(settings.value("nPruneSize").toInt());
std::string prune_val = prune ? ToString(prune_target_mib) : "0";
if (force) {
- m_node.forceSetArg("-prune", prune_val);
+ gArgs.ForceSetArg("-prune", prune_val);
return;
}
- if (!m_node.softSetArg("-prune", prune_val)) {
+ if (!gArgs.SoftSetArg("-prune", prune_val)) {
addOverriddenOption("-prune");
}
}
@@ -353,7 +353,7 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
break;
case MapPortUPnP: // core option - can be changed on-the-fly
settings.setValue("fUseUPnP", value.toBool());
- m_node.mapPort(value.toBool());
+ node().mapPort(value.toBool());
break;
case MinimizeOnClose:
fMinimizeOnClose = value.toBool();
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index 14fdf9046e..3d9e7bbb80 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -11,6 +11,8 @@
#include <QAbstractListModel>
+#include <assert.h>
+
namespace interfaces {
class Node;
}
@@ -39,7 +41,7 @@ class OptionsModel : public QAbstractListModel
Q_OBJECT
public:
- explicit OptionsModel(interfaces::Node& node, QObject *parent = nullptr, bool resetSettings = false);
+ explicit OptionsModel(QObject *parent = nullptr, bool resetSettings = false);
enum OptionID {
StartAtStartup, // bool
@@ -92,10 +94,11 @@ public:
void setRestartRequired(bool fRequired);
bool isRestartRequired() const;
- interfaces::Node& node() const { return m_node; }
+ interfaces::Node& node() const { assert(m_node); return *m_node; }
+ void setNode(interfaces::Node& node) { assert(!m_node); m_node = &node; }
private:
- interfaces::Node& m_node;
+ interfaces::Node* m_node = nullptr;
/* Qt-only settings */
bool fHideTrayIcon;
bool fMinimizeToTray;
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index a1da85bda7..8679ced685 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -74,7 +74,7 @@ static QSet<QString> savedPaymentRequests;
// Warning: ipcSendCommandLine() is called early in init,
// so don't use "Q_EMIT message()", but "QMessageBox::"!
//
-void PaymentServer::ipcParseCommandLine(interfaces::Node& node, int argc, char* argv[])
+void PaymentServer::ipcParseCommandLine(int argc, char* argv[])
{
for (int i = 1; i < argc; i++)
{
@@ -97,11 +97,11 @@ void PaymentServer::ipcParseCommandLine(interfaces::Node& node, int argc, char*
auto tempChainParams = CreateChainParams(CBaseChainParams::MAIN);
if (IsValidDestinationString(r.address.toStdString(), *tempChainParams)) {
- node.selectParams(CBaseChainParams::MAIN);
+ SelectParams(CBaseChainParams::MAIN);
} else {
tempChainParams = CreateChainParams(CBaseChainParams::TESTNET);
if (IsValidDestinationString(r.address.toStdString(), *tempChainParams)) {
- node.selectParams(CBaseChainParams::TESTNET);
+ SelectParams(CBaseChainParams::TESTNET);
}
}
}
diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h
index 154f4a7ea6..eaf2bafe59 100644
--- a/src/qt/paymentserver.h
+++ b/src/qt/paymentserver.h
@@ -61,7 +61,7 @@ class PaymentServer : public QObject
public:
// Parse URIs on command line
// Returns false on error
- static void ipcParseCommandLine(interfaces::Node& node, int argc, char *argv[]);
+ static void ipcParseCommandLine(int argc, char *argv[]);
// Returns true if there were URIs on the command line
// which were successfully sent to an already-running
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index 5debded4ea..d374d610ee 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -242,22 +242,6 @@ void ReceiveCoinsDialog::resizeEvent(QResizeEvent *event)
columnResizingFixer->stretchColumnWidth(RecentRequestsTableModel::Message);
}
-void ReceiveCoinsDialog::keyPressEvent(QKeyEvent *event)
-{
- if (event->key() == Qt::Key_Return)
- {
- // press return -> submit form
- if (ui->reqLabel->hasFocus() || ui->reqAmount->hasFocus() || ui->reqMessage->hasFocus())
- {
- event->ignore();
- on_receiveButton_clicked();
- return;
- }
- }
-
- this->QDialog::keyPressEvent(event);
-}
-
QModelIndex ReceiveCoinsDialog::selectedRow()
{
if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h
index 2f48cd58f0..27455e2906 100644
--- a/src/qt/receivecoinsdialog.h
+++ b/src/qt/receivecoinsdialog.h
@@ -49,9 +49,6 @@ public Q_SLOTS:
void reject() override;
void accept() override;
-protected:
- virtual void keyPressEvent(QKeyEvent *event) override;
-
private:
Ui::ReceiveCoinsDialog *ui;
GUIUtil::TableViewLastColumnResizingFixer *columnResizingFixer;
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index 6e6b2b8466..bd63d6e7fb 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -24,8 +24,8 @@
#include <QScreen>
-SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const NetworkStyle *networkStyle) :
- QWidget(nullptr, f), curAlignment(0), m_node(node)
+SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle) :
+ QWidget(nullptr, f), curAlignment(0)
{
// set reference point, paddings
int paddingRight = 50;
@@ -124,7 +124,6 @@ SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const Netw
setFixedSize(r.size());
move(QGuiApplication::primaryScreen()->geometry().center() - r.center());
- subscribeToCoreSignals();
installEventFilter(this);
GUIUtil::handleCloseWindowShortcut(this);
@@ -132,14 +131,28 @@ SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const Netw
SplashScreen::~SplashScreen()
{
- unsubscribeFromCoreSignals();
+ if (m_node) unsubscribeFromCoreSignals();
+}
+
+void SplashScreen::setNode(interfaces::Node& node)
+{
+ assert(!m_node);
+ m_node = &node;
+ subscribeToCoreSignals();
+ if (m_shutdown) m_node->startShutdown();
+}
+
+void SplashScreen::shutdown()
+{
+ m_shutdown = true;
+ if (m_node) m_node->startShutdown();
}
bool SplashScreen::eventFilter(QObject * obj, QEvent * ev) {
if (ev->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
if (keyEvent->key() == Qt::Key_Q) {
- m_node.startShutdown();
+ shutdown();
}
}
return QObject::eventFilter(obj, ev);
@@ -183,10 +196,10 @@ void SplashScreen::ConnectWallet(std::unique_ptr<interfaces::Wallet> wallet)
void SplashScreen::subscribeToCoreSignals()
{
// Connect signals to client
- m_handler_init_message = m_node.handleInitMessage(std::bind(InitMessage, this, std::placeholders::_1));
- m_handler_show_progress = m_node.handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
+ m_handler_init_message = m_node->handleInitMessage(std::bind(InitMessage, this, std::placeholders::_1));
+ m_handler_show_progress = m_node->handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
#ifdef ENABLE_WALLET
- m_handler_load_wallet = m_node.handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) { ConnectWallet(std::move(wallet)); });
+ m_handler_load_wallet = m_node->handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) { ConnectWallet(std::move(wallet)); });
#endif
}
@@ -221,6 +234,6 @@ void SplashScreen::paintEvent(QPaintEvent *event)
void SplashScreen::closeEvent(QCloseEvent *event)
{
- m_node.startShutdown(); // allows an "emergency" shutdown during startup
+ shutdown(); // allows an "emergency" shutdown during startup
event->ignore();
}
diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h
index 3158524117..2213b02c55 100644
--- a/src/qt/splashscreen.h
+++ b/src/qt/splashscreen.h
@@ -28,8 +28,9 @@ class SplashScreen : public QWidget
Q_OBJECT
public:
- explicit SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const NetworkStyle *networkStyle);
+ explicit SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle);
~SplashScreen();
+ void setNode(interfaces::Node& node);
protected:
void paintEvent(QPaintEvent *event) override;
@@ -50,6 +51,8 @@ private:
void subscribeToCoreSignals();
/** Disconnect core signals to splash screen */
void unsubscribeFromCoreSignals();
+ /** Initiate shutdown */
+ void shutdown();
/** Connect wallet signals to splash screen */
void ConnectWallet(std::unique_ptr<interfaces::Wallet> wallet);
@@ -58,7 +61,8 @@ private:
QColor curColor;
int curAlignment;
- interfaces::Node& m_node;
+ interfaces::Node* m_node = nullptr;
+ bool m_shutdown = false;
std::unique_ptr<interfaces::Handler> m_handler_init_message;
std::unique_ptr<interfaces::Handler> m_handler_show_progress;
std::unique_ptr<interfaces::Handler> m_handler_load_wallet;
diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp
index 035c8196bc..84f981dff3 100644
--- a/src/qt/test/addressbooktests.cpp
+++ b/src/qt/test/addressbooktests.cpp
@@ -108,7 +108,7 @@ void TestAddAddressesToSendBook(interfaces::Node& node)
// Initialize relevant QT models.
std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
- OptionsModel optionsModel(node);
+ OptionsModel optionsModel;
ClientModel clientModel(node, &optionsModel);
AddWallet(wallet);
WalletModel walletModel(interfaces::MakeWallet(wallet), clientModel, platformStyle.get());
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index 031913bd02..86356b43c8 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -68,11 +68,11 @@ int main(int argc, char* argv[])
// Don't remove this, it's needed to access
// QApplication:: and QCoreApplication:: in the tests
- BitcoinApplication app(*node);
+ BitcoinApplication app;
+ app.setNode(*node);
app.setApplicationName("Bitcoin-Qt-test");
- node->setupServerArgs(); // Make gArgs available in the NodeContext
- node->context()->args->ClearArgs(); // Clear added args again
+ app.node().context()->args = &gArgs; // Make gArgs available in the NodeContext
AppTests app_tests(app);
if (QTest::qExec(&app_tests) != 0) {
fInvalid = true;
@@ -81,7 +81,7 @@ int main(int argc, char* argv[])
if (QTest::qExec(&test1) != 0) {
fInvalid = true;
}
- RPCNestedTests test3(*node);
+ RPCNestedTests test3(app.node());
if (QTest::qExec(&test3) != 0) {
fInvalid = true;
}
@@ -90,11 +90,11 @@ int main(int argc, char* argv[])
fInvalid = true;
}
#ifdef ENABLE_WALLET
- WalletTests test5(*node);
+ WalletTests test5(app.node());
if (QTest::qExec(&test5) != 0) {
fInvalid = true;
}
- AddressBookTests test6(*node);
+ AddressBookTests test6(app.node());
if (QTest::qExec(&test6) != 0) {
fInvalid = true;
}
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index 475fd589af..adcfe0d25c 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -163,7 +163,7 @@ void TestGUI(interfaces::Node& node)
std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
SendCoinsDialog sendCoinsDialog(platformStyle.get());
TransactionView transactionView(platformStyle.get());
- OptionsModel optionsModel(node);
+ OptionsModel optionsModel;
ClientModel clientModel(node, &optionsModel);
AddWallet(wallet);
WalletModel walletModel(interfaces::MakeWallet(wallet), clientModel, platformStyle.get());
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index 01922cf996..b7f85446f4 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -28,7 +28,7 @@
#include <QVBoxLayout>
/** "Help message" or "About" dialog box */
-HelpMessageDialog::HelpMessageDialog(interfaces::Node& node, QWidget *parent, bool about) :
+HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) :
QDialog(parent),
ui(new Ui::HelpMessageDialog)
{
diff --git a/src/qt/utilitydialog.h b/src/qt/utilitydialog.h
index 425b468f40..d2a5d5f67f 100644
--- a/src/qt/utilitydialog.h
+++ b/src/qt/utilitydialog.h
@@ -12,10 +12,6 @@ QT_BEGIN_NAMESPACE
class QMainWindow;
QT_END_NAMESPACE
-namespace interfaces {
- class Node;
-}
-
namespace Ui {
class HelpMessageDialog;
}
@@ -26,7 +22,7 @@ class HelpMessageDialog : public QDialog
Q_OBJECT
public:
- explicit HelpMessageDialog(interfaces::Node& node, QWidget *parent, bool about);
+ explicit HelpMessageDialog(QWidget *parent, bool about);
~HelpMessageDialog();
void printToConsole();
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 868ff88d08..033e00daf5 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -556,7 +556,10 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request)
RPCResult::Type::ARR, "", "",
{{RPCResult::Type::STR_HEX, "", "The transaction id of an in-mempool ancestor transaction"}}},
RPCResult{"for verbose = true",
- RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
+ RPCResult::Type::OBJ_DYN, "", "",
+ {
+ {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
+ }},
},
RPCExamples{
HelpExampleCli("getmempoolancestors", "\"mytxid\"")
@@ -588,7 +591,6 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request)
for (CTxMemPool::txiter ancestorIt : setAncestors) {
o.push_back(ancestorIt->GetTx().GetHash().ToString());
}
-
return o;
} else {
UniValue o(UniValue::VOBJ);
@@ -1739,7 +1741,7 @@ static UniValue getblockstats(const JSONRPCRequest& request)
{RPCResult::Type::NUM, "total_size", "Total size of all non-coinbase transactions"},
{RPCResult::Type::NUM, "total_weight", "Total weight of all non-coinbase transactions divided by segwit scale factor (4)"},
{RPCResult::Type::NUM, "totalfee", "The fee total"},
- {RPCResult::Type::NUM, "txs", "The number of transactions (excluding coinbase)"},
+ {RPCResult::Type::NUM, "txs", "The number of transactions (including coinbase)"},
{RPCResult::Type::NUM, "utxo_increase", "The increase/decrease in the number of unspent outputs"},
{RPCResult::Type::NUM, "utxo_size_inc", "The increase/decrease in size for the utxo index (not discounting op_return and similar)"},
}},
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 76aa9dbfc1..d9cc6f8832 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -511,12 +511,13 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
{"mode", RPCArg::Type::STR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "This must be set to \"template\", \"proposal\" (see BIP 23), or omitted"},
{"capabilities", RPCArg::Type::ARR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "A list of strings",
{
- {"support", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid'"},
+ {"str", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "client side supported feature, 'longpoll', 'coinbasevalue', 'proposal', 'serverlist', 'workid'"},
},
},
{"rules", RPCArg::Type::ARR, RPCArg::Optional::NO, "A list of strings",
{
- {"support", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "client side supported softfork deployment"},
+ {"segwit", RPCArg::Type::STR, RPCArg::Optional::NO, "(literal) indicates client side segwit support"},
+ {"str", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "other client side supported softfork deployment"},
},
},
},
@@ -528,7 +529,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
{RPCResult::Type::NUM, "version", "The preferred block version"},
{RPCResult::Type::ARR, "rules", "specific block rules that are to be enforced",
{
- {RPCResult::Type::STR, "", "rulename"},
+ {RPCResult::Type::STR, "", "name of a rule the client must understand to some extent; see BIP 9 for format"},
}},
{RPCResult::Type::OBJ_DYN, "vbavailable", "set of pending, supported versionbit (BIP 9) softfork deployments",
{
@@ -536,7 +537,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
}},
{RPCResult::Type::NUM, "vbrequired", "bit mask of versionbits the server requires set in submissions"},
{RPCResult::Type::STR, "previousblockhash", "The hash of current highest block"},
- {RPCResult::Type::ARR, "", "contents of non-coinbase transactions that should be included in the next block",
+ {RPCResult::Type::ARR, "transactions", "contents of non-coinbase transactions that should be included in the next block",
{
{RPCResult::Type::OBJ, "", "",
{
@@ -552,15 +553,12 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
{RPCResult::Type::NUM, "weight", "total transaction weight, as counted for purposes of block limits"},
}},
}},
- {RPCResult::Type::OBJ, "coinbaseaux", "data that should be included in the coinbase's scriptSig content",
+ {RPCResult::Type::OBJ_DYN, "coinbaseaux", "data that should be included in the coinbase's scriptSig content",
{
- {RPCResult::Type::ELISION, "", ""},
+ {RPCResult::Type::STR_HEX, "key", "values must be in the coinbase (keys may be ignored)"},
}},
{RPCResult::Type::NUM, "coinbasevalue", "maximum allowable input to coinbase transaction, including the generation award and transaction fees (in satoshis)"},
- {RPCResult::Type::OBJ, "coinbasetxn", "information for coinbase transaction",
- {
- {RPCResult::Type::ELISION, "", ""},
- }},
+ {RPCResult::Type::STR, "longpollid", "an id to include with a request to longpoll on an update to this template"},
{RPCResult::Type::STR, "target", "The hash target"},
{RPCResult::Type::NUM_TIME, "mintime", "The minimum timestamp appropriate for the next block time, expressed in " + UNIX_EPOCH_TIME},
{RPCResult::Type::ARR, "mutable", "list of ways the block template may be changed",
@@ -574,6 +572,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
{RPCResult::Type::NUM_TIME, "curtime", "current timestamp in " + UNIX_EPOCH_TIME},
{RPCResult::Type::STR, "bits", "compressed target of next block"},
{RPCResult::Type::NUM, "height", "The height of the next block"},
+ {RPCResult::Type::STR, "default_witness_commitment", /* optional */ true, "a valid witness commitment for the unmodified block template"}
}},
RPCExamples{
HelpExampleCli("getblocktemplate", "'{\"rules\": [\"segwit\"]}'")
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index ff31bee1e3..0c982317f5 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -4,6 +4,8 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <httpserver.h>
+#include <index/blockfilterindex.h>
+#include <index/txindex.h>
#include <interfaces/chain.h>
#include <key_io.h>
#include <node/context.h>
@@ -636,6 +638,60 @@ static RPCHelpMan echo(const std::string& name)
static RPCHelpMan echo() { return echo("echo"); }
static RPCHelpMan echojson() { return echo("echojson"); }
+static UniValue SummaryToJSON(const IndexSummary&& summary, std::string index_name)
+{
+ UniValue ret_summary(UniValue::VOBJ);
+ if (!index_name.empty() && index_name != summary.name) return ret_summary;
+
+ UniValue entry(UniValue::VOBJ);
+ entry.pushKV("synced", summary.synced);
+ entry.pushKV("best_block_height", summary.best_block_height);
+ ret_summary.pushKV(summary.name, entry);
+ return ret_summary;
+}
+
+static RPCHelpMan getindexinfo()
+{
+ return RPCHelpMan{"getindexinfo",
+ "\nReturns the status of one or all available indices currently running in the node.\n",
+ {
+ {"index_name", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Filter results for an index with a specific name."},
+ },
+ RPCResult{
+ RPCResult::Type::OBJ, "", "", {
+ {
+ RPCResult::Type::OBJ, "name", "The name of the index",
+ {
+ {RPCResult::Type::BOOL, "synced", "Whether the index is synced or not"},
+ {RPCResult::Type::NUM, "best_block_height", "The block height to which the index is synced"},
+ }
+ },
+ },
+ },
+ RPCExamples{
+ HelpExampleCli("getindexinfo", "")
+ + HelpExampleRpc("getindexinfo", "")
+ + HelpExampleCli("getindexinfo", "txindex")
+ + HelpExampleRpc("getindexinfo", "txindex")
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
+ UniValue result(UniValue::VOBJ);
+ const std::string index_name = request.params[0].isNull() ? "" : request.params[0].get_str();
+
+ if (g_txindex) {
+ result.pushKVs(SummaryToJSON(g_txindex->GetSummary(), index_name));
+ }
+
+ ForEachBlockFilterIndex([&result, &index_name](const BlockFilterIndex& index) {
+ result.pushKVs(SummaryToJSON(index.GetSummary(), index_name));
+ });
+
+ return result;
+},
+ };
+}
+
void RegisterMiscRPCCommands(CRPCTable &t)
{
// clang-format off
@@ -650,6 +706,7 @@ static const CRPCCommand commands[] =
{ "util", "getdescriptorinfo", &getdescriptorinfo, {"descriptor"} },
{ "util", "verifymessage", &verifymessage, {"address","signature","message"} },
{ "util", "signmessagewithprivkey", &signmessagewithprivkey, {"privkey","message"} },
+ { "util", "getindexinfo", &getindexinfo, {"index_name"} },
/* Not shown in help */
{ "hidden", "setmocktime", &setmocktime, {"timestamp"}},
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 9bd7c15992..7e2052c7cb 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -100,6 +100,8 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
{RPCResult::Type::BOOL, "relaytxes", "Whether peer has asked us to relay transactions to it"},
{RPCResult::Type::NUM_TIME, "lastsend", "The " + UNIX_EPOCH_TIME + " of the last send"},
{RPCResult::Type::NUM_TIME, "lastrecv", "The " + UNIX_EPOCH_TIME + " of the last receive"},
+ {RPCResult::Type::NUM_TIME, "last_transaction", "The " + UNIX_EPOCH_TIME + " of the last valid transaction received from this peer"},
+ {RPCResult::Type::NUM_TIME, "last_block", "The " + UNIX_EPOCH_TIME + " of the last block received from this peer"},
{RPCResult::Type::NUM, "bytessent", "The total bytes sent"},
{RPCResult::Type::NUM, "bytesrecv", "The total bytes received"},
{RPCResult::Type::NUM_TIME, "conntime", "The " + UNIX_EPOCH_TIME + " of the connection"},
@@ -169,6 +171,8 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
obj.pushKV("relaytxes", stats.fRelayTxes);
obj.pushKV("lastsend", stats.nLastSend);
obj.pushKV("lastrecv", stats.nLastRecv);
+ obj.pushKV("last_transaction", stats.nLastTXTime);
+ obj.pushKV("last_block", stats.nLastBlockTime);
obj.pushKV("bytessent", stats.nSendBytes);
obj.pushKV("bytesrecv", stats.nRecvBytes);
obj.pushKV("conntime", stats.nTimeConnected);
@@ -193,7 +197,7 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
if (fStateStats) {
if (IsDeprecatedRPCEnabled("banscore")) {
// banscore is deprecated in v0.21 for removal in v0.22
- obj.pushKV("banscore", statestats.nMisbehavior);
+ obj.pushKV("banscore", statestats.m_misbehavior_score);
}
obj.pushKV("synced_headers", statestats.nSyncHeight);
obj.pushKV("synced_blocks", statestats.nCommonHeight);
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index abc8168c55..d6988ee3ac 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -1300,7 +1300,7 @@ UniValue combinepsbt(const JSONRPCRequest& request)
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << merged_psbt;
- return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size());
+ return EncodeBase64(MakeUCharSpan(ssTx));
}
UniValue finalizepsbt(const JSONRPCRequest& request)
@@ -1435,7 +1435,7 @@ UniValue createpsbt(const JSONRPCRequest& request)
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << psbtx;
- return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size());
+ return EncodeBase64(MakeUCharSpan(ssTx));
}
UniValue converttopsbt(const JSONRPCRequest& request)
@@ -1502,7 +1502,7 @@ UniValue converttopsbt(const JSONRPCRequest& request)
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << psbtx;
- return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size());
+ return EncodeBase64(MakeUCharSpan(ssTx));
}
UniValue utxoupdatepsbt(const JSONRPCRequest& request)
@@ -1590,7 +1590,7 @@ UniValue utxoupdatepsbt(const JSONRPCRequest& request)
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << psbtx;
- return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size());
+ return EncodeBase64(MakeUCharSpan(ssTx));
}
UniValue joinpsbts(const JSONRPCRequest& request)
@@ -1683,7 +1683,7 @@ UniValue joinpsbts(const JSONRPCRequest& request)
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << shuffled_psbt;
- return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size());
+ return EncodeBase64(MakeUCharSpan(ssTx));
}
UniValue analyzepsbt(const JSONRPCRequest& request)
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 39feb4ccc9..7b2457a5e3 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -1258,34 +1258,37 @@ public:
}
};
+/** Compute the (single) SHA256 of the concatenation of all prevouts of a tx. */
template <class T>
-uint256 GetPrevoutHash(const T& txTo)
+uint256 GetPrevoutsSHA256(const T& txTo)
{
CHashWriter ss(SER_GETHASH, 0);
for (const auto& txin : txTo.vin) {
ss << txin.prevout;
}
- return ss.GetHash();
+ return ss.GetSHA256();
}
+/** Compute the (single) SHA256 of the concatenation of all nSequences of a tx. */
template <class T>
-uint256 GetSequenceHash(const T& txTo)
+uint256 GetSequencesSHA256(const T& txTo)
{
CHashWriter ss(SER_GETHASH, 0);
for (const auto& txin : txTo.vin) {
ss << txin.nSequence;
}
- return ss.GetHash();
+ return ss.GetSHA256();
}
+/** Compute the (single) SHA256 of the concatenation of all txouts of a tx. */
template <class T>
-uint256 GetOutputsHash(const T& txTo)
+uint256 GetOutputsSHA256(const T& txTo)
{
CHashWriter ss(SER_GETHASH, 0);
for (const auto& txout : txTo.vout) {
ss << txout;
}
- return ss.GetHash();
+ return ss.GetSHA256();
}
} // namespace
@@ -1297,9 +1300,9 @@ void PrecomputedTransactionData::Init(const T& txTo)
// Cache is calculated only for transactions with witness
if (txTo.HasWitness()) {
- hashPrevouts = GetPrevoutHash(txTo);
- hashSequence = GetSequenceHash(txTo);
- hashOutputs = GetOutputsHash(txTo);
+ hashPrevouts = SHA256Uint256(GetPrevoutsSHA256(txTo));
+ hashSequence = SHA256Uint256(GetSequencesSHA256(txTo));
+ hashOutputs = SHA256Uint256(GetOutputsSHA256(txTo));
}
m_ready = true;
@@ -1329,16 +1332,16 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
const bool cacheready = cache && cache->m_ready;
if (!(nHashType & SIGHASH_ANYONECANPAY)) {
- hashPrevouts = cacheready ? cache->hashPrevouts : GetPrevoutHash(txTo);
+ hashPrevouts = cacheready ? cache->hashPrevouts : SHA256Uint256(GetPrevoutsSHA256(txTo));
}
if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
- hashSequence = cacheready ? cache->hashSequence : GetSequenceHash(txTo);
+ hashSequence = cacheready ? cache->hashSequence : SHA256Uint256(GetSequencesSHA256(txTo));
}
if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
- hashOutputs = cacheready ? cache->hashOutputs : GetOutputsHash(txTo);
+ hashOutputs = cacheready ? cache->hashOutputs : SHA256Uint256(GetOutputsSHA256(txTo));
} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
CHashWriter ss(SER_GETHASH, 0);
ss << txTo.vout[nIn];
diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp
index b4f392116c..26de780f29 100644
--- a/src/support/lockedpool.cpp
+++ b/src/support/lockedpool.cpp
@@ -10,7 +10,6 @@
#endif
#ifdef WIN32
-#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index 0115803e58..93bfa88024 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -80,7 +80,7 @@ BOOST_FIXTURE_TEST_SUITE(denialofservice_tests, TestingSetup)
BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
{
auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
- auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), nullptr, *m_node.scheduler, *m_node.chainman, *m_node.mempool);
+ auto peerLogic = MakeUnique<PeerLogicValidation>(*connman, nullptr, *m_node.scheduler, *m_node.chainman, *m_node.mempool);
// Mock an outbound peer
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
@@ -150,7 +150,7 @@ static void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerLogicValidat
BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
{
auto connman = MakeUnique<CConnmanTest>(0x1337, 0x1337);
- auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), nullptr, *m_node.scheduler, *m_node.chainman, *m_node.mempool);
+ auto peerLogic = MakeUnique<PeerLogicValidation>(*connman, nullptr, *m_node.scheduler, *m_node.chainman, *m_node.mempool);
const Consensus::Params& consensusParams = Params().GetConsensus();
constexpr int max_outbound_full_relay = MAX_OUTBOUND_FULL_RELAY_CONNECTIONS;
@@ -223,7 +223,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
{
auto banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
- auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool);
+ auto peerLogic = MakeUnique<PeerLogicValidation>(*connman, banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool);
banman->ClearBanned();
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
@@ -232,10 +232,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
peerLogic->InitializeNode(&dummyNode1);
dummyNode1.nVersion = 1;
dummyNode1.fSuccessfullyConnected = true;
- {
- LOCK(cs_main);
- Misbehaving(dummyNode1.GetId(), DISCOURAGEMENT_THRESHOLD); // Should be discouraged
- }
+ Misbehaving(dummyNode1.GetId(), DISCOURAGEMENT_THRESHOLD); // Should be discouraged
{
LOCK(dummyNode1.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode1));
@@ -249,20 +246,14 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
peerLogic->InitializeNode(&dummyNode2);
dummyNode2.nVersion = 1;
dummyNode2.fSuccessfullyConnected = true;
- {
- LOCK(cs_main);
- Misbehaving(dummyNode2.GetId(), DISCOURAGEMENT_THRESHOLD - 1);
- }
+ Misbehaving(dummyNode2.GetId(), DISCOURAGEMENT_THRESHOLD - 1);
{
LOCK(dummyNode2.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode2));
}
BOOST_CHECK(!banman->IsDiscouraged(addr2)); // 2 not discouraged yet...
BOOST_CHECK(banman->IsDiscouraged(addr1)); // ... but 1 still should be
- {
- LOCK(cs_main);
- Misbehaving(dummyNode2.GetId(), 1); // 2 reaches discouragement threshold
- }
+ Misbehaving(dummyNode2.GetId(), 1); // 2 reaches discouragement threshold
{
LOCK(dummyNode2.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode2));
@@ -279,7 +270,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
{
auto banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
- auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool);
+ auto peerLogic = MakeUnique<PeerLogicValidation>(*connman, banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool);
banman->ClearBanned();
int64_t nStartTime = GetTime();
@@ -292,10 +283,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
dummyNode.nVersion = 1;
dummyNode.fSuccessfullyConnected = true;
- {
- LOCK(cs_main);
- Misbehaving(dummyNode.GetId(), DISCOURAGEMENT_THRESHOLD);
- }
+ Misbehaving(dummyNode.GetId(), DISCOURAGEMENT_THRESHOLD);
{
LOCK(dummyNode.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode));
diff --git a/src/test/fuzz/asmap.cpp b/src/test/fuzz/asmap.cpp
index 40ca01bd9f..e3aefa18a3 100644
--- a/src/test/fuzz/asmap.cpp
+++ b/src/test/fuzz/asmap.cpp
@@ -33,7 +33,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
if (buffer.size() < 1 + 3 + 4) return;
int asmap_size = 3 + (buffer[0] & 127);
bool ipv6 = buffer[0] & 128;
- int addr_size = ipv6 ? 16 : 4;
+ const size_t addr_size = ipv6 ? ADDR_IPV6_SIZE : ADDR_IPV4_SIZE;
if (buffer.size() < size_t(1 + asmap_size + addr_size)) return;
std::vector<bool> asmap = ipv6 ? IPV6_PREFIX_ASMAP : IPV4_PREFIX_ASMAP;
asmap.reserve(asmap.size() + 8 * asmap_size);
@@ -43,7 +43,17 @@ void test_one_input(const std::vector<uint8_t>& buffer)
}
}
if (!SanityCheckASMap(asmap)) return;
+
+ const uint8_t* addr_data = buffer.data() + 1 + asmap_size;
CNetAddr net_addr;
- net_addr.SetRaw(ipv6 ? NET_IPV6 : NET_IPV4, buffer.data() + 1 + asmap_size);
+ if (ipv6) {
+ assert(addr_size == ADDR_IPV6_SIZE);
+ net_addr.SetLegacyIPv6(Span<const uint8_t>(addr_data, addr_size));
+ } else {
+ assert(addr_size == ADDR_IPV4_SIZE);
+ in_addr ipv4;
+ memcpy(&ipv4, addr_data, addr_size);
+ net_addr.SetIP(CNetAddr{ipv4});
+ }
(void)net_addr.GetMappedAS(asmap);
}
diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp
new file mode 100644
index 0000000000..1ff9d6b286
--- /dev/null
+++ b/src/test/fuzz/net.cpp
@@ -0,0 +1,156 @@
+// Copyright (c) 2020 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 <chainparams.h>
+#include <chainparamsbase.h>
+#include <net.h>
+#include <net_permissions.h>
+#include <netaddress.h>
+#include <optional.h>
+#include <protocol.h>
+#include <random.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+void initialize()
+{
+ static const BasicTestingSetup basic_testing_setup;
+}
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+
+ const std::optional<CAddress> address = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
+ if (!address) {
+ return;
+ }
+ const std::optional<CAddress> address_bind = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
+ if (!address_bind) {
+ return;
+ }
+
+ CNode node{fuzzed_data_provider.ConsumeIntegral<NodeId>(),
+ static_cast<ServiceFlags>(fuzzed_data_provider.ConsumeIntegral<uint64_t>()),
+ fuzzed_data_provider.ConsumeIntegral<int>(),
+ INVALID_SOCKET,
+ *address,
+ fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
+ fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
+ *address_bind,
+ fuzzed_data_provider.ConsumeRandomLengthString(32),
+ fuzzed_data_provider.PickValueInArray({ConnectionType::INBOUND, ConnectionType::OUTBOUND, ConnectionType::MANUAL, ConnectionType::FEELER, ConnectionType::BLOCK_RELAY, ConnectionType::ADDR_FETCH})};
+ while (fuzzed_data_provider.ConsumeBool()) {
+ switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 12)) {
+ case 0: {
+ node.CloseSocketDisconnect();
+ break;
+ }
+ case 1: {
+ node.MaybeSetAddrName(fuzzed_data_provider.ConsumeRandomLengthString(32));
+ break;
+ }
+ case 2: {
+ node.SetSendVersion(fuzzed_data_provider.ConsumeIntegral<int>());
+ break;
+ }
+ case 3: {
+ const std::vector<bool> asmap = ConsumeRandomLengthIntegralVector<bool>(fuzzed_data_provider, 128);
+ if (!SanityCheckASMap(asmap)) {
+ break;
+ }
+ CNodeStats stats;
+ node.copyStats(stats, asmap);
+ break;
+ }
+ case 4: {
+ node.SetRecvVersion(fuzzed_data_provider.ConsumeIntegral<int>());
+ break;
+ }
+ case 5: {
+ const CNode* add_ref_node = node.AddRef();
+ assert(add_ref_node == &node);
+ break;
+ }
+ case 6: {
+ if (node.GetRefCount() > 0) {
+ node.Release();
+ }
+ break;
+ }
+ case 7: {
+ if (node.m_addr_known == nullptr) {
+ break;
+ }
+ const std::optional<CAddress> addr_opt = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
+ if (!addr_opt) {
+ break;
+ }
+ node.AddAddressKnown(*addr_opt);
+ break;
+ }
+ case 8: {
+ if (node.m_addr_known == nullptr) {
+ break;
+ }
+ const std::optional<CAddress> addr_opt = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
+ if (!addr_opt) {
+ break;
+ }
+ FastRandomContext fast_random_context{ConsumeUInt256(fuzzed_data_provider)};
+ node.PushAddress(*addr_opt, fast_random_context);
+ break;
+ }
+ case 9: {
+ const std::optional<CInv> inv_opt = ConsumeDeserializable<CInv>(fuzzed_data_provider);
+ if (!inv_opt) {
+ break;
+ }
+ node.AddKnownTx(inv_opt->hash);
+ break;
+ }
+ case 10: {
+ node.PushTxInventory(ConsumeUInt256(fuzzed_data_provider));
+ break;
+ }
+ case 11: {
+ const std::optional<CService> service_opt = ConsumeDeserializable<CService>(fuzzed_data_provider);
+ if (!service_opt) {
+ break;
+ }
+ node.SetAddrLocal(*service_opt);
+ break;
+ }
+ case 12: {
+ const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ bool complete;
+ node.ReceiveMsgBytes((const char*)b.data(), b.size(), complete);
+ break;
+ }
+ }
+ }
+
+ (void)node.GetAddrLocal();
+ (void)node.GetAddrName();
+ (void)node.GetId();
+ (void)node.GetLocalNonce();
+ (void)node.GetLocalServices();
+ (void)node.GetMyStartingHeight();
+ (void)node.GetRecvVersion();
+ const int ref_count = node.GetRefCount();
+ assert(ref_count >= 0);
+ (void)node.GetSendVersion();
+ (void)node.IsAddrRelayPeer();
+
+ const NetPermissionFlags net_permission_flags = fuzzed_data_provider.ConsumeBool() ?
+ fuzzed_data_provider.PickValueInArray<NetPermissionFlags>({NetPermissionFlags::PF_NONE, NetPermissionFlags::PF_BLOOMFILTER, NetPermissionFlags::PF_RELAY, NetPermissionFlags::PF_FORCERELAY, NetPermissionFlags::PF_NOBAN, NetPermissionFlags::PF_MEMPOOL, NetPermissionFlags::PF_ISIMPLICIT, NetPermissionFlags::PF_ALL}) :
+ static_cast<NetPermissionFlags>(fuzzed_data_provider.ConsumeIntegral<uint32_t>());
+ (void)node.HasPermission(net_permission_flags);
+}
diff --git a/src/test/fuzz/netaddress.cpp b/src/test/fuzz/netaddress.cpp
index 2901c704f6..8252f38726 100644
--- a/src/test/fuzz/netaddress.cpp
+++ b/src/test/fuzz/netaddress.cpp
@@ -17,9 +17,6 @@ void test_one_input(const std::vector<uint8_t>& buffer)
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const CNetAddr net_addr = ConsumeNetAddr(fuzzed_data_provider);
- for (int i = 0; i < 15; ++i) {
- (void)net_addr.GetByte(i);
- }
(void)net_addr.GetHash();
(void)net_addr.GetNetClass();
if (net_addr.GetNetwork() == Network::NET_IPV4) {
@@ -78,7 +75,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
(void)net_addr.ToString();
(void)net_addr.ToStringIP();
- const CSubNet sub_net{net_addr, fuzzed_data_provider.ConsumeIntegral<int32_t>()};
+ const CSubNet sub_net{net_addr, fuzzed_data_provider.ConsumeIntegral<uint8_t>()};
(void)sub_net.IsValid();
(void)sub_net.ToString();
diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp
index 677b87a47a..ec09acc6c6 100644
--- a/src/test/fuzz/process_message.cpp
+++ b/src/test/fuzz/process_message.cpp
@@ -30,18 +30,6 @@
#include <string>
#include <vector>
-void ProcessMessage(
- CNode& pfrom,
- const std::string& msg_type,
- CDataStream& vRecv,
- const std::chrono::microseconds time_received,
- const CChainParams& chainparams,
- ChainstateManager& chainman,
- CTxMemPool& mempool,
- CConnman& connman,
- BanMan* banman,
- const std::atomic<bool>& interruptMsgProc);
-
namespace {
#ifdef MESSAGE_TYPE
@@ -87,10 +75,9 @@ void test_one_input(const std::vector<uint8_t>& buffer)
connman.AddTestNode(p2p_node);
g_setup->m_node.peer_logic->InitializeNode(&p2p_node);
try {
- ProcessMessage(p2p_node, random_message_type, random_bytes_data_stream, GetTime<std::chrono::microseconds>(),
- Params(), *g_setup->m_node.chainman, *g_setup->m_node.mempool,
- *g_setup->m_node.connman, g_setup->m_node.banman.get(),
- std::atomic<bool>{false});
+ g_setup->m_node.peer_logic->ProcessMessage(p2p_node, random_message_type, random_bytes_data_stream,
+ GetTime<std::chrono::microseconds>(), Params(),
+ std::atomic<bool>{false});
} catch (const std::ios_base::failure&) {
}
SyncWithValidationInterfaceQueue();
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index 9f9552edb9..ed6093a8a8 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -257,7 +257,7 @@ CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept
CSubNet ConsumeSubNet(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
- return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<int32_t>()};
+ return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint8_t>()};
}
void InitializeFuzzingContext(const std::string& chain_name = CBaseChainParams::REGTEST)
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index 317000c771..917ae571f5 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -13,8 +13,10 @@
#include <streams.h>
#include <test/util/setup_common.h>
#include <util/memory.h>
+#include <util/strencodings.h>
#include <util/string.h>
#include <util/system.h>
+#include <version.h>
#include <boost/test/unit_test.hpp>
@@ -188,6 +190,78 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
BOOST_CHECK(pnode2->IsInboundConn() == true);
}
+BOOST_AUTO_TEST_CASE(cnetaddr_basic)
+{
+ CNetAddr addr;
+
+ // IPv4, INADDR_ANY
+ BOOST_REQUIRE(LookupHost("0.0.0.0", addr, false));
+ BOOST_REQUIRE(!addr.IsValid());
+ BOOST_REQUIRE(addr.IsIPv4());
+
+ BOOST_CHECK(addr.IsBindAny());
+ BOOST_CHECK_EQUAL(addr.ToString(), "0.0.0.0");
+
+ // IPv4, INADDR_NONE
+ BOOST_REQUIRE(LookupHost("255.255.255.255", addr, false));
+ BOOST_REQUIRE(!addr.IsValid());
+ BOOST_REQUIRE(addr.IsIPv4());
+
+ BOOST_CHECK(!addr.IsBindAny());
+ BOOST_CHECK_EQUAL(addr.ToString(), "255.255.255.255");
+
+ // IPv4, casual
+ BOOST_REQUIRE(LookupHost("12.34.56.78", addr, false));
+ BOOST_REQUIRE(addr.IsValid());
+ BOOST_REQUIRE(addr.IsIPv4());
+
+ BOOST_CHECK(!addr.IsBindAny());
+ BOOST_CHECK_EQUAL(addr.ToString(), "12.34.56.78");
+
+ // IPv6, in6addr_any
+ BOOST_REQUIRE(LookupHost("::", addr, false));
+ BOOST_REQUIRE(!addr.IsValid());
+ BOOST_REQUIRE(addr.IsIPv6());
+
+ BOOST_CHECK(addr.IsBindAny());
+ BOOST_CHECK_EQUAL(addr.ToString(), "::");
+
+ // IPv6, casual
+ BOOST_REQUIRE(LookupHost("1122:3344:5566:7788:9900:aabb:ccdd:eeff", addr, false));
+ BOOST_REQUIRE(addr.IsValid());
+ BOOST_REQUIRE(addr.IsIPv6());
+
+ BOOST_CHECK(!addr.IsBindAny());
+ BOOST_CHECK_EQUAL(addr.ToString(), "1122:3344:5566:7788:9900:aabb:ccdd:eeff");
+
+ // TORv2
+ addr.SetSpecial("6hzph5hv6337r6p2.onion");
+ BOOST_REQUIRE(addr.IsValid());
+ BOOST_REQUIRE(addr.IsTor());
+
+ BOOST_CHECK(!addr.IsBindAny());
+ BOOST_CHECK_EQUAL(addr.ToString(), "6hzph5hv6337r6p2.onion");
+
+ // Internal
+ addr.SetInternal("esffpp");
+ BOOST_REQUIRE(!addr.IsValid()); // "internal" is considered invalid
+ BOOST_REQUIRE(addr.IsInternal());
+
+ BOOST_CHECK(!addr.IsBindAny());
+ BOOST_CHECK_EQUAL(addr.ToString(), "esffpvrt3wpeaygy.internal");
+}
+
+BOOST_AUTO_TEST_CASE(cnetaddr_serialize)
+{
+ CNetAddr addr;
+ CDataStream s(SER_NETWORK, PROTOCOL_VERSION);
+
+ addr.SetInternal("a");
+ s << addr;
+ BOOST_CHECK_EQUAL(HexStr(s), "fd6b88c08724ca978112ca1bbdcafac2");
+ s.clear();
+}
+
// prior to PR #14728, this test triggers an undefined behavior
BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test)
{
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index 49073ea657..6681c92bb5 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -185,6 +185,7 @@ BOOST_AUTO_TEST_CASE(subnet_test)
BOOST_CHECK(!ResolveSubNet("1.2.3.0/-1").IsValid());
BOOST_CHECK(ResolveSubNet("1.2.3.0/32").IsValid());
BOOST_CHECK(!ResolveSubNet("1.2.3.0/33").IsValid());
+ BOOST_CHECK(!ResolveSubNet("1.2.3.0/300").IsValid());
BOOST_CHECK(ResolveSubNet("1:2:3:4:5:6:7:8/0").IsValid());
BOOST_CHECK(ResolveSubNet("1:2:3:4:5:6:7:8/33").IsValid());
BOOST_CHECK(!ResolveSubNet("1:2:3:4:5:6:7:8/-1").IsValid());
@@ -216,6 +217,11 @@ BOOST_AUTO_TEST_CASE(subnet_test)
BOOST_CHECK(CSubNet(ResolveIP("1:2:3:4:5:6:7:8")).Match(ResolveIP("1:2:3:4:5:6:7:8")));
BOOST_CHECK(!CSubNet(ResolveIP("1:2:3:4:5:6:7:8")).Match(ResolveIP("1:2:3:4:5:6:7:9")));
BOOST_CHECK(CSubNet(ResolveIP("1:2:3:4:5:6:7:8")).ToString() == "1:2:3:4:5:6:7:8/128");
+ // IPv4 address with IPv6 netmask or the other way around.
+ BOOST_CHECK(!CSubNet(ResolveIP("1.1.1.1"), ResolveIP("ffff::")).IsValid());
+ BOOST_CHECK(!CSubNet(ResolveIP("::1"), ResolveIP("255.0.0.0")).IsValid());
+ // Can't subnet TOR (or any other non-IPv4 and non-IPv6 network).
+ BOOST_CHECK(!CSubNet(ResolveIP("5wyqrzbvrdsumnok.onion"), ResolveIP("255.0.0.0")).IsValid());
subnet = ResolveSubNet("1.2.3.4/255.255.255.255");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/32");
@@ -290,11 +296,13 @@ BOOST_AUTO_TEST_CASE(subnet_test)
BOOST_CHECK_EQUAL(subnet.ToString(), "1::/16");
subnet = ResolveSubNet("1:2:3:4:5:6:7:8/0000:0000:0000:0000:0000:0000:0000:0000");
BOOST_CHECK_EQUAL(subnet.ToString(), "::/0");
+ // Invalid netmasks (with 1-bits after 0-bits)
subnet = ResolveSubNet("1.2.3.4/255.255.232.0");
- BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/255.255.232.0");
+ BOOST_CHECK(!subnet.IsValid());
+ subnet = ResolveSubNet("1.2.3.4/255.0.255.255");
+ BOOST_CHECK(!subnet.IsValid());
subnet = ResolveSubNet("1:2:3:4:5:6:7:8/ffff:ffff:ffff:fffe:ffff:ffff:ffff:ff0f");
- BOOST_CHECK_EQUAL(subnet.ToString(), "1:2:3:4:5:6:7:8/ffff:ffff:ffff:fffe:ffff:ffff:ffff:ff0f");
-
+ BOOST_CHECK(!subnet.IsValid());
}
BOOST_AUTO_TEST_CASE(netbase_getgroup)
@@ -428,7 +436,8 @@ BOOST_AUTO_TEST_CASE(netbase_dont_resolve_strings_with_embedded_nul_characters)
BOOST_CHECK(!LookupSubNet(std::string("1.2.3.0/24\0", 11), ret));
BOOST_CHECK(!LookupSubNet(std::string("1.2.3.0/24\0example.com", 22), ret));
BOOST_CHECK(!LookupSubNet(std::string("1.2.3.0/24\0example.com\0", 23), ret));
- BOOST_CHECK(LookupSubNet(std::string("5wyqrzbvrdsumnok.onion", 22), ret));
+ // We only do subnetting for IPv4 and IPv6
+ BOOST_CHECK(!LookupSubNet(std::string("5wyqrzbvrdsumnok.onion", 22), ret));
BOOST_CHECK(!LookupSubNet(std::string("5wyqrzbvrdsumnok.onion\0", 23), ret));
BOOST_CHECK(!LookupSubNet(std::string("5wyqrzbvrdsumnok.onion\0example.com", 34), ret));
BOOST_CHECK(!LookupSubNet(std::string("5wyqrzbvrdsumnok.onion\0example.com\0", 35), ret));
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index b2ae1cb845..d9a00c2205 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -97,8 +97,8 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
SelectParams(chainName);
SeedInsecureRand();
if (G_TEST_LOG_FUN) LogInstance().PushBackCallback(G_TEST_LOG_FUN);
- InitLogging();
- AppInitParameterInteraction();
+ InitLogging(*m_node.args);
+ AppInitParameterInteraction(*m_node.args);
LogInstance().StartLogging();
SHA256AutoDetect();
ECC_Start();
@@ -168,7 +168,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
m_node.mempool->setSanityCheck(1.0);
m_node.banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
m_node.connman = MakeUnique<CConnman>(0x1337, 0x1337); // Deterministic randomness for tests.
- m_node.peer_logic = MakeUnique<PeerLogicValidation>(m_node.connman.get(), m_node.banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool);
+ m_node.peer_logic = MakeUnique<PeerLogicValidation>(*m_node.connman, m_node.banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool);
{
CConnman::Options options;
options.m_msgproc = m_node.peer_logic.get();
@@ -196,49 +196,34 @@ TestingSetup::~TestingSetup()
TestChain100Setup::TestChain100Setup()
{
- // CreateAndProcessBlock() does not support building SegWit blocks, so don't activate in these tests.
- // TODO: fix the code to support SegWit blocks.
- gArgs.ForceSetArg("-segwitheight", "432");
- // Need to recreate chainparams
- SelectParams(CBaseChainParams::REGTEST);
-
// Generate a 100-block chain:
coinbaseKey.MakeNewKey(true);
- CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
- for (int i = 0; i < COINBASE_MATURITY; i++)
- {
+ CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
+ for (int i = 0; i < COINBASE_MATURITY; i++) {
std::vector<CMutableTransaction> noTxns;
CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey);
m_coinbase_txns.push_back(b.vtx[0]);
}
}
-// Create a new block with just given transactions, coinbase paying to
-// scriptPubKey, and try to add it to the current chain.
CBlock TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey)
{
const CChainParams& chainparams = Params();
- std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(*m_node.mempool, chainparams).CreateNewBlock(scriptPubKey);
- CBlock& block = pblocktemplate->block;
+ CTxMemPool empty_pool;
+ CBlock block = BlockAssembler(empty_pool, chainparams).CreateNewBlock(scriptPubKey)->block;
- // Replace mempool-selected txns with just coinbase plus passed-in txns:
- block.vtx.resize(1);
- for (const CMutableTransaction& tx : txns)
+ Assert(block.vtx.size() == 1);
+ for (const CMutableTransaction& tx : txns) {
block.vtx.push_back(MakeTransactionRef(tx));
- // IncrementExtraNonce creates a valid coinbase and merkleRoot
- {
- LOCK(cs_main);
- unsigned int extraNonce = 0;
- IncrementExtraNonce(&block, ::ChainActive().Tip(), extraNonce);
}
+ RegenerateCommitments(block);
while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;
std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(block);
Assert(m_node.chainman)->ProcessNewBlock(chainparams, shared_pblock, true, nullptr);
- CBlock result = block;
- return result;
+ return block;
}
TestChain100Setup::~TestChain100Setup()
@@ -246,8 +231,8 @@ TestChain100Setup::~TestChain100Setup()
gArgs.ForceSetArg("-segwitheight", "0");
}
-
-CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx) {
+CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction& tx)
+{
return FromTx(MakeTransactionRef(tx));
}
diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h
index 78b279e42a..22f5d6d936 100644
--- a/src/test/util/setup_common.h
+++ b/src/test/util/setup_common.h
@@ -102,15 +102,16 @@ class CBlock;
struct CMutableTransaction;
class CScript;
-//
-// Testing fixture that pre-creates a
-// 100-block REGTEST-mode block chain
-//
+/**
+ * Testing fixture that pre-creates a 100-block REGTEST-mode block chain
+ */
struct TestChain100Setup : public RegTestingSetup {
TestChain100Setup();
- // Create a new block with just given transactions, coinbase paying to
- // scriptPubKey, and try to add it to the current chain.
+ /**
+ * Create a new block with just given transactions, coinbase paying to
+ * scriptPubKey, and try to add it to the current chain.
+ */
CBlock CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns,
const CScript& scriptPubKey);
diff --git a/src/threadsafety.h b/src/threadsafety.h
index 5f2c40bac6..52bf83b676 100644
--- a/src/threadsafety.h
+++ b/src/threadsafety.h
@@ -18,9 +18,7 @@
#define LOCKABLE __attribute__((lockable))
#define SCOPED_LOCKABLE __attribute__((scoped_lockable))
#define GUARDED_BY(x) __attribute__((guarded_by(x)))
-#define GUARDED_VAR __attribute__((guarded_var))
#define PT_GUARDED_BY(x) __attribute__((pt_guarded_by(x)))
-#define PT_GUARDED_VAR __attribute__((pt_guarded_var))
#define ACQUIRED_AFTER(...) __attribute__((acquired_after(__VA_ARGS__)))
#define ACQUIRED_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__)))
#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__((exclusive_lock_function(__VA_ARGS__)))
@@ -33,14 +31,12 @@
#define EXCLUSIVE_LOCKS_REQUIRED(...) __attribute__((exclusive_locks_required(__VA_ARGS__)))
#define SHARED_LOCKS_REQUIRED(...) __attribute__((shared_locks_required(__VA_ARGS__)))
#define NO_THREAD_SAFETY_ANALYSIS __attribute__((no_thread_safety_analysis))
-#define ASSERT_EXCLUSIVE_LOCK(...) __attribute((assert_exclusive_lock(__VA_ARGS__)))
+#define ASSERT_EXCLUSIVE_LOCK(...) __attribute__((assert_exclusive_lock(__VA_ARGS__)))
#else
#define LOCKABLE
#define SCOPED_LOCKABLE
#define GUARDED_BY(x)
-#define GUARDED_VAR
#define PT_GUARDED_BY(x)
-#define PT_GUARDED_VAR
#define ACQUIRED_AFTER(...)
#define ACQUIRED_BEFORE(...)
#define EXCLUSIVE_LOCK_FUNCTION(...)
diff --git a/src/util/message.cpp b/src/util/message.cpp
index 1e7128d225..e1d5cff48c 100644
--- a/src/util/message.cpp
+++ b/src/util/message.cpp
@@ -64,7 +64,7 @@ bool MessageSign(
return false;
}
- signature = EncodeBase64(signature_bytes.data(), signature_bytes.size());
+ signature = EncodeBase64(signature_bytes);
return true;
}
diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp
index 4d51b9045e..079a4529a3 100644
--- a/src/util/strencodings.cpp
+++ b/src/util/strencodings.cpp
@@ -126,20 +126,20 @@ void SplitHostPort(std::string in, int &portOut, std::string &hostOut) {
hostOut = in;
}
-std::string EncodeBase64(const unsigned char* pch, size_t len)
+std::string EncodeBase64(Span<const unsigned char> input)
{
static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
std::string str;
- str.reserve(((len + 2) / 3) * 4);
- ConvertBits<8, 6, true>([&](int v) { str += pbase64[v]; }, pch, pch + len);
+ str.reserve(((input.size() + 2) / 3) * 4);
+ ConvertBits<8, 6, true>([&](int v) { str += pbase64[v]; }, input.begin(), input.end());
while (str.size() % 4) str += '=';
return str;
}
std::string EncodeBase64(const std::string& str)
{
- return EncodeBase64((const unsigned char*)str.data(), str.size());
+ return EncodeBase64(MakeUCharSpan(str));
}
std::vector<unsigned char> DecodeBase64(const char* p, bool* pf_invalid)
@@ -201,20 +201,20 @@ std::string DecodeBase64(const std::string& str, bool* pf_invalid)
return std::string((const char*)vchRet.data(), vchRet.size());
}
-std::string EncodeBase32(const unsigned char* pch, size_t len)
+std::string EncodeBase32(Span<const unsigned char> input)
{
static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567";
std::string str;
- str.reserve(((len + 4) / 5) * 8);
- ConvertBits<8, 5, true>([&](int v) { str += pbase32[v]; }, pch, pch + len);
+ str.reserve(((input.size() + 4) / 5) * 8);
+ ConvertBits<8, 5, true>([&](int v) { str += pbase32[v]; }, input.begin(), input.end());
while (str.size() % 8) str += '=';
return str;
}
std::string EncodeBase32(const std::string& str)
{
- return EncodeBase32((const unsigned char*)str.data(), str.size());
+ return EncodeBase32(MakeUCharSpan(str));
}
std::vector<unsigned char> DecodeBase32(const char* p, bool* pf_invalid)
@@ -318,6 +318,18 @@ bool ParseInt64(const std::string& str, int64_t *out)
n <= std::numeric_limits<int64_t>::max();
}
+bool ParseUInt8(const std::string& str, uint8_t *out)
+{
+ uint32_t u32;
+ if (!ParseUInt32(str, &u32) || u32 > std::numeric_limits<uint8_t>::max()) {
+ return false;
+ }
+ if (out != nullptr) {
+ *out = static_cast<uint8_t>(u32);
+ }
+ return true;
+}
+
bool ParseUInt32(const std::string& str, uint32_t *out)
{
if (!ParsePrechecks(str))
diff --git a/src/util/strencodings.h b/src/util/strencodings.h
index b4bbaeebf6..1519214140 100644
--- a/src/util/strencodings.h
+++ b/src/util/strencodings.h
@@ -48,11 +48,11 @@ bool IsHex(const std::string& str);
bool IsHexNumber(const std::string& str);
std::vector<unsigned char> DecodeBase64(const char* p, bool* pf_invalid = nullptr);
std::string DecodeBase64(const std::string& str, bool* pf_invalid = nullptr);
-std::string EncodeBase64(const unsigned char* pch, size_t len);
+std::string EncodeBase64(Span<const unsigned char> input);
std::string EncodeBase64(const std::string& str);
std::vector<unsigned char> DecodeBase32(const char* p, bool* pf_invalid = nullptr);
std::string DecodeBase32(const std::string& str, bool* pf_invalid = nullptr);
-std::string EncodeBase32(const unsigned char* pch, size_t len);
+std::string EncodeBase32(Span<const unsigned char> input);
std::string EncodeBase32(const std::string& str);
void SplitHostPort(std::string in, int& portOut, std::string& hostOut);
@@ -99,6 +99,13 @@ NODISCARD bool ParseInt32(const std::string& str, int32_t *out);
NODISCARD bool ParseInt64(const std::string& str, int64_t *out);
/**
+ * Convert decimal string to unsigned 8-bit integer with strict parse error feedback.
+ * @returns true if the entire string could be parsed as valid integer,
+ * false if not the entire string could be parsed or when overflow or underflow occurred.
+ */
+NODISCARD bool ParseUInt8(const std::string& str, uint8_t *out);
+
+/**
* Convert decimal string to unsigned 32-bit integer with strict parse error feedback.
* @returns true if the entire string could be parsed as valid integer,
* false if not the entire string could be parsed or when overflow or underflow occurred.
diff --git a/src/util/system.cpp b/src/util/system.cpp
index f5931b5ff1..999937d906 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -48,12 +48,6 @@
#pragma warning(disable:4717)
#endif
-#ifdef _WIN32_IE
-#undef _WIN32_IE
-#endif
-#define _WIN32_IE 0x0501
-
-#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 7a03c4f544..17512265b5 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -2836,6 +2836,15 @@ static UniValue listunspent(const JSONRPCRequest& request)
if (!request.params[4].isNull()) {
const UniValue& options = request.params[4].get_obj();
+ RPCTypeCheckObj(options,
+ {
+ {"minimumAmount", UniValueType()},
+ {"maximumAmount", UniValueType()},
+ {"minimumSumAmount", UniValueType()},
+ {"maximumCount", UniValueType(UniValue::VNUM)},
+ },
+ true, true);
+
if (options.exists("minimumAmount"))
nMinimumAmount = AmountFromValue(options["minimumAmount"]);
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index c132a4be42..0627522eea 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -276,7 +276,7 @@ std::string COutput::ToString() const
const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
{
- LOCK(cs_wallet);
+ AssertLockHeld(cs_wallet);
std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(hash);
if (it == mapWallet.end())
return nullptr;
@@ -1210,15 +1210,13 @@ void CWallet::BlockUntilSyncedToCurrentChain() const {
isminetype CWallet::IsMine(const CTxIn &txin) const
{
+ AssertLockHeld(cs_wallet);
+ std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
+ if (mi != mapWallet.end())
{
- LOCK(cs_wallet);
- std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
- if (mi != mapWallet.end())
- {
- const CWalletTx& prev = (*mi).second;
- if (txin.prevout.n < prev.tx->vout.size())
- return IsMine(prev.tx->vout[txin.prevout.n]);
- }
+ const CWalletTx& prev = (*mi).second;
+ if (txin.prevout.n < prev.tx->vout.size())
+ return IsMine(prev.tx->vout[txin.prevout.n]);
}
return ISMINE_NO;
}
@@ -1243,16 +1241,19 @@ CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const
isminetype CWallet::IsMine(const CTxOut& txout) const
{
+ AssertLockHeld(cs_wallet);
return IsMine(txout.scriptPubKey);
}
isminetype CWallet::IsMine(const CTxDestination& dest) const
{
+ AssertLockHeld(cs_wallet);
return IsMine(GetScriptForDestination(dest));
}
isminetype CWallet::IsMine(const CScript& script) const
{
+ AssertLockHeld(cs_wallet);
isminetype result = ISMINE_NO;
for (const auto& spk_man_pair : m_spk_managers) {
result = std::max(result, spk_man_pair.second->IsMine(script));
@@ -1264,6 +1265,7 @@ CAmount CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter) cons
{
if (!MoneyRange(txout.nValue))
throw std::runtime_error(std::string(__func__) + ": value out of range");
+ LOCK(cs_wallet);
return ((IsMine(txout) & filter) ? txout.nValue : 0);
}
@@ -1281,13 +1283,12 @@ bool CWallet::IsChange(const CScript& script) const
// a better way of identifying which outputs are 'the send' and which are
// 'the change' will need to be implemented (maybe extend CWalletTx to remember
// which output, if any, was change).
+ AssertLockHeld(cs_wallet);
if (IsMine(script))
{
CTxDestination address;
if (!ExtractDestination(script, address))
return true;
-
- LOCK(cs_wallet);
if (!FindAddressBookEntry(address)) {
return true;
}
@@ -1297,6 +1298,7 @@ bool CWallet::IsChange(const CScript& script) const
CAmount CWallet::GetChange(const CTxOut& txout) const
{
+ AssertLockHeld(cs_wallet);
if (!MoneyRange(txout.nValue))
throw std::runtime_error(std::string(__func__) + ": value out of range");
return (IsChange(txout) ? txout.nValue : 0);
@@ -1304,6 +1306,7 @@ CAmount CWallet::GetChange(const CTxOut& txout) const
bool CWallet::IsMine(const CTransaction& tx) const
{
+ AssertLockHeld(cs_wallet);
for (const CTxOut& txout : tx.vout)
if (IsMine(txout))
return true;
@@ -1362,6 +1365,7 @@ CAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) c
CAmount CWallet::GetChange(const CTransaction& tx) const
{
+ LOCK(cs_wallet);
CAmount nChange = 0;
for (const CTxOut& txout : tx.vout)
{
@@ -1597,6 +1601,7 @@ void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
nFee = nDebit - nValueOut;
}
+ LOCK(pwallet->cs_wallet);
// Sent/received.
for (unsigned int i = 0; i < tx->vout.size(); ++i)
{
@@ -1983,6 +1988,7 @@ bool CWalletTx::IsTrusted(std::set<uint256>& trusted_parents) const
if (!InMempool()) return false;
// Trusted if all inputs are from us and are in the mempool:
+ LOCK(pwallet->cs_wallet);
for (const CTxIn& txin : tx->vin)
{
// Transactions not sent by us: not trusted
@@ -3194,6 +3200,7 @@ DBErrors CWallet::ZapWalletTx(std::list<CWalletTx>& vWtx)
bool CWallet::SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::string& strPurpose)
{
bool fUpdated = false;
+ bool is_mine;
{
LOCK(cs_wallet);
std::map<CTxDestination, CAddressBookData>::iterator mi = m_address_book.find(address);
@@ -3201,8 +3208,9 @@ bool CWallet::SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& add
m_address_book[address].SetLabel(strName);
if (!strPurpose.empty()) /* update purpose only if requested */
m_address_book[address].purpose = strPurpose;
+ is_mine = IsMine(address) != ISMINE_NO;
}
- NotifyAddressBookChanged(this, address, strName, IsMine(address) != ISMINE_NO,
+ NotifyAddressBookChanged(this, address, strName, is_mine,
strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) );
if (!strPurpose.empty() && !batch.WritePurpose(EncodeDestination(address), strPurpose))
return false;
@@ -3217,17 +3225,16 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& s
bool CWallet::DelAddressBook(const CTxDestination& address)
{
- // If we want to delete receiving addresses, we need to take care that DestData "used" (and possibly newer DestData) gets preserved (and the "deleted" address transformed into a change entry instead of actually being deleted)
- // NOTE: This isn't a problem for sending addresses because they never have any DestData yet!
- // When adding new DestData, it should be considered here whether to retain or delete it (or move it?).
- if (IsMine(address)) {
- WalletLogPrintf("%s called with IsMine address, NOT SUPPORTED. Please report this bug! %s\n", __func__, PACKAGE_BUGREPORT);
- return false;
- }
-
+ bool is_mine;
{
LOCK(cs_wallet);
-
+ // If we want to delete receiving addresses, we need to take care that DestData "used" (and possibly newer DestData) gets preserved (and the "deleted" address transformed into a change entry instead of actually being deleted)
+ // NOTE: This isn't a problem for sending addresses because they never have any DestData yet!
+ // When adding new DestData, it should be considered here whether to retain or delete it (or move it?).
+ if (IsMine(address)) {
+ WalletLogPrintf("%s called with IsMine address, NOT SUPPORTED. Please report this bug! %s\n", __func__, PACKAGE_BUGREPORT);
+ return false;
+ }
// Delete destdata tuples associated with address
std::string strAddress = EncodeDestination(address);
for (const std::pair<const std::string, std::string> &item : m_address_book[address].destdata)
@@ -3235,9 +3242,10 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
WalletBatch(*database).EraseDestData(strAddress, item.first);
}
m_address_book.erase(address);
+ is_mine = IsMine(address) != ISMINE_NO;
}
- NotifyAddressBookChanged(this, address, "", IsMine(address) != ISMINE_NO, "", CT_DELETED);
+ NotifyAddressBookChanged(this, address, "", is_mine, "", CT_DELETED);
WalletBatch(*database).ErasePurpose(EncodeDestination(address));
return WalletBatch(*database).EraseName(EncodeDestination(address));
@@ -3364,9 +3372,6 @@ std::map<CTxDestination, CAmount> CWallet::GetAddressBalances() const
continue;
CAmount n = IsSpent(walletEntry.first, i) ? 0 : wtx.tx->vout[i].nValue;
-
- if (!balances.count(addr))
- balances[addr] = 0;
balances[addr] += n;
}
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 2f9d301000..f421de0cf2 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -805,7 +805,7 @@ public:
/** Interface for accessing chain state. */
interfaces::Chain& chain() const { assert(m_chain); return *m_chain; }
- const CWalletTx* GetWalletTx(const uint256& hash) const;
+ const CWalletTx* GetWalletTx(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! check whether we are allowed to upgrade (or already support) to the named feature
bool CanSupportFeature(enum WalletFeature wf) const override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; }
@@ -1051,20 +1051,20 @@ public:
bool GetNewDestination(const OutputType type, const std::string label, CTxDestination& dest, std::string& error);
bool GetNewChangeDestination(const OutputType type, CTxDestination& dest, std::string& error);
- isminetype IsMine(const CTxDestination& dest) const;
- isminetype IsMine(const CScript& script) const;
- isminetype IsMine(const CTxIn& txin) const;
+ isminetype IsMine(const CTxDestination& dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ isminetype IsMine(const CScript& script) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ isminetype IsMine(const CTxIn& txin) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/**
* Returns amount of debit if the input matches the
* filter, otherwise returns 0
*/
CAmount GetDebit(const CTxIn& txin, const isminefilter& filter) const;
- isminetype IsMine(const CTxOut& txout) const;
+ isminetype IsMine(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
CAmount GetCredit(const CTxOut& txout, const isminefilter& filter) const;
- bool IsChange(const CTxOut& txout) const;
- bool IsChange(const CScript& script) const;
- CAmount GetChange(const CTxOut& txout) const;
- bool IsMine(const CTransaction& tx) const;
+ bool IsChange(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ bool IsChange(const CScript& script) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ CAmount GetChange(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ bool IsMine(const CTransaction& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** should probably be renamed to IsRelevantToMe */
bool IsFromMe(const CTransaction& tx) const;
CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const;