aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.test.include35
-rw-r--r--src/blockfilter.h8
-rw-r--r--src/interfaces/node.cpp10
-rw-r--r--src/net.cpp76
-rw-r--r--src/net_processing.cpp91
-rw-r--r--src/protocol.cpp29
-rw-r--r--src/protocol.h18
-rw-r--r--src/psbt.h2
-rw-r--r--src/qt/bitcoin.cpp4
-rw-r--r--src/qt/guiutil.cpp8
-rw-r--r--src/qt/transactiontablemodel.cpp2
-rw-r--r--src/qt/walletview.cpp2
-rw-r--r--src/rpc/blockchain.cpp2
-rw-r--r--src/rpc/mining.cpp2
-rw-r--r--src/rpc/server.cpp25
-rw-r--r--src/rpc/util.cpp8
-rw-r--r--src/test/fuzz/script.cpp39
-rw-r--r--src/test/fuzz/script_bitcoin_consensus.cpp31
-rw-r--r--src/test/fuzz/script_descriptor_cache.cpp42
-rw-r--r--src/test/fuzz/script_interpreter.cpp41
-rw-r--r--src/test/fuzz/script_sigcache.cpp45
-rw-r--r--src/test/fuzz/script_sign.cpp149
-rw-r--r--src/test/fuzz/string.cpp5
-rw-r--r--src/test/fuzz/util.h57
-rw-r--r--src/test/getarg_tests.cpp133
-rw-r--r--src/test/raii_event_tests.cpp19
-rw-r--r--src/txmempool.h6
-rw-r--r--src/validation.cpp14
28 files changed, 753 insertions, 150 deletions
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 2480cdadbb..7909cb4a0f 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -110,9 +110,14 @@ FUZZ_TARGETS = \
test/fuzz/rbf \
test/fuzz/rolling_bloom_filter \
test/fuzz/script \
+ test/fuzz/script_bitcoin_consensus \
+ test/fuzz/script_descriptor_cache \
test/fuzz/script_deserialize \
test/fuzz/script_flags \
+ test/fuzz/script_interpreter \
test/fuzz/script_ops \
+ test/fuzz/script_sigcache \
+ test/fuzz/script_sign \
test/fuzz/scriptnum_ops \
test/fuzz/service_deserialize \
test/fuzz/signature_checker \
@@ -941,6 +946,18 @@ test_fuzz_script_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_script_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
test_fuzz_script_SOURCES = test/fuzz/script.cpp
+test_fuzz_script_bitcoin_consensus_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+test_fuzz_script_bitcoin_consensus_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_script_bitcoin_consensus_LDADD = $(FUZZ_SUITE_LD_COMMON)
+test_fuzz_script_bitcoin_consensus_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_script_bitcoin_consensus_SOURCES = test/fuzz/script_bitcoin_consensus.cpp
+
+test_fuzz_script_descriptor_cache_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+test_fuzz_script_descriptor_cache_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_script_descriptor_cache_LDADD = $(FUZZ_SUITE_LD_COMMON)
+test_fuzz_script_descriptor_cache_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_script_descriptor_cache_SOURCES = test/fuzz/script_descriptor_cache.cpp
+
test_fuzz_script_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DSCRIPT_DESERIALIZE=1
test_fuzz_script_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_script_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
@@ -953,12 +970,30 @@ test_fuzz_script_flags_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_script_flags_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
test_fuzz_script_flags_SOURCES = test/fuzz/script_flags.cpp
+test_fuzz_script_interpreter_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+test_fuzz_script_interpreter_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_script_interpreter_LDADD = $(FUZZ_SUITE_LD_COMMON)
+test_fuzz_script_interpreter_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_script_interpreter_SOURCES = test/fuzz/script_interpreter.cpp
+
test_fuzz_script_ops_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_script_ops_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_script_ops_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_script_ops_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
test_fuzz_script_ops_SOURCES = test/fuzz/script_ops.cpp
+test_fuzz_script_sigcache_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+test_fuzz_script_sigcache_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_script_sigcache_LDADD = $(FUZZ_SUITE_LD_COMMON)
+test_fuzz_script_sigcache_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_script_sigcache_SOURCES = test/fuzz/script_sigcache.cpp
+
+test_fuzz_script_sign_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+test_fuzz_script_sign_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_script_sign_LDADD = $(FUZZ_SUITE_LD_COMMON)
+test_fuzz_script_sign_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_script_sign_SOURCES = test/fuzz/script_sign.cpp
+
test_fuzz_scriptnum_ops_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_scriptnum_ops_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_scriptnum_ops_LDADD = $(FUZZ_SUITE_LD_COMMON)
diff --git a/src/blockfilter.h b/src/blockfilter.h
index ff8744b217..96cefbf3b2 100644
--- a/src/blockfilter.h
+++ b/src/blockfilter.h
@@ -144,8 +144,8 @@ public:
template <typename Stream>
void Serialize(Stream& s) const {
- s << m_block_hash
- << static_cast<uint8_t>(m_filter_type)
+ s << static_cast<uint8_t>(m_filter_type)
+ << m_block_hash
<< m_filter.GetEncoded();
}
@@ -154,8 +154,8 @@ public:
std::vector<unsigned char> encoded_filter;
uint8_t filter_type;
- s >> m_block_hash
- >> filter_type
+ s >> filter_type
+ >> m_block_hash
>> encoded_filter;
m_filter_type = static_cast<BlockFilterType>(filter_type);
diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp
index ca1435fe60..bd1b36fea5 100644
--- a/src/interfaces/node.cpp
+++ b/src/interfaces/node.cpp
@@ -88,7 +88,15 @@ public:
Interrupt(m_context);
Shutdown(m_context);
}
- void startShutdown() override { StartShutdown(); }
+ void startShutdown() override
+ {
+ StartShutdown();
+ // Stop RPC for clean shutdown if any of waitfor* commands is executed.
+ if (gArgs.GetBoolArg("-server", false)) {
+ InterruptRPC();
+ StopRPC();
+ }
+ }
bool shutdownRequested() override { return ShutdownRequested(); }
void mapPort(bool use_upnp) override
{
diff --git a/src/net.cpp b/src/net.cpp
index c9cfb67ec8..707412bb32 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -52,6 +52,12 @@ static constexpr std::chrono::minutes DUMP_PEERS_INTERVAL{15};
/** Number of DNS seeds to query when the number of connections is low. */
static constexpr int DNSSEEDS_TO_QUERY_AT_ONCE = 3;
+/** How long to delay before querying DNS seeds
+ */
+static constexpr std::chrono::seconds DNSSEEDS_DELAY_FEW_PEERS{11}; // 11sec
+static constexpr std::chrono::seconds DNSSEEDS_DELAY_MANY_PEERS{300}; // 5min
+static constexpr int DNSSEEDS_DELAY_PEER_THRESHOLD = 1000; // "many" vs "few" peers -- you should only get this many if you've been on the live network
+
// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.
#define FEELER_SLEEP_WINDOW 1
@@ -1587,31 +1593,67 @@ void CConnman::ThreadDNSAddressSeed()
if (gArgs.GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED)) {
// When -forcednsseed is provided, query all.
seeds_right_now = seeds.size();
+ } else if (addrman.size() == 0) {
+ // If we have no known peers, query all.
+ seeds_right_now = seeds.size();
}
+ // goal: only query DNS seed if address need is acute
+ // * If we have a reasonable number of peers in addrman, spend
+ // some time trying them first. This improves user privacy by
+ // creating fewer identifying DNS requests, reduces trust by
+ // giving seeds less influence on the network topology, and
+ // reduces traffic to the seeds.
+ // * When querying DNS seeds query a few at once, this ensures
+ // that we don't give DNS seeds the ability to eclipse nodes
+ // that query them.
+ // * If we continue having problems, eventually query all the
+ // DNS seeds, and if that fails too, also try the fixed seeds.
+ // (done in ThreadOpenConnections)
+ const std::chrono::seconds seeds_wait_time = (addrman.size() >= DNSSEEDS_DELAY_PEER_THRESHOLD ? DNSSEEDS_DELAY_MANY_PEERS : DNSSEEDS_DELAY_FEW_PEERS);
+
for (const std::string& seed : seeds) {
- // goal: only query DNS seed if address need is acute
- // Avoiding DNS seeds when we don't need them improves user privacy by
- // creating fewer identifying DNS requests, reduces trust by giving seeds
- // less influence on the network topology, and reduces traffic to the seeds.
- if (addrman.size() > 0 && seeds_right_now == 0) {
- if (!interruptNet.sleep_for(std::chrono::seconds(11))) return;
+ if (seeds_right_now == 0) {
+ seeds_right_now += DNSSEEDS_TO_QUERY_AT_ONCE;
- LOCK(cs_vNodes);
- int nRelevant = 0;
- for (const CNode* pnode : vNodes) {
- nRelevant += pnode->fSuccessfullyConnected && !pnode->fFeeler && !pnode->fOneShot && !pnode->m_manual_connection && !pnode->fInbound;
- }
- if (nRelevant >= 2) {
- LogPrintf("P2P peers available. Skipped DNS seeding.\n");
- return;
+ if (addrman.size() > 0) {
+ LogPrintf("Waiting %d seconds before querying DNS seeds.\n", seeds_wait_time.count());
+ std::chrono::seconds to_wait = seeds_wait_time;
+ while (to_wait.count() > 0) {
+ std::chrono::seconds w = std::min(DNSSEEDS_DELAY_FEW_PEERS, to_wait);
+ if (!interruptNet.sleep_for(w)) return;
+ to_wait -= w;
+
+ int nRelevant = 0;
+ {
+ LOCK(cs_vNodes);
+ for (const CNode* pnode : vNodes) {
+ nRelevant += pnode->fSuccessfullyConnected && !pnode->fFeeler && !pnode->fOneShot && !pnode->m_manual_connection && !pnode->fInbound;
+ }
+ }
+ if (nRelevant >= 2) {
+ if (found > 0) {
+ LogPrintf("%d addresses found from DNS seeds\n", found);
+ LogPrintf("P2P peers available. Finished DNS seeding.\n");
+ } else {
+ LogPrintf("P2P peers available. Skipped DNS seeding.\n");
+ }
+ return;
+ }
+ }
}
- seeds_right_now += DNSSEEDS_TO_QUERY_AT_ONCE;
}
- if (interruptNet) {
- return;
+ if (interruptNet) return;
+
+ // hold off on querying seeds if p2p network deactivated
+ if (!fNetworkActive) {
+ LogPrintf("Waiting for network to be reactivated before querying DNS seeds.\n");
+ do {
+ if (!interruptNet.sleep_for(std::chrono::seconds{1})) return;
+ } while (!fNetworkActive);
}
+
LogPrintf("Loading addresses from DNS seed %s\n", seed);
if (HaveNameProxy()) {
AddOneShot(seed);
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 159036a237..404b33a977 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -129,6 +129,8 @@ static constexpr unsigned int INVENTORY_BROADCAST_MAX = 7 * INVENTORY_BROADCAST_
static constexpr unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60;
/** Maximum feefilter broadcast delay after significant change. */
static constexpr unsigned int MAX_FEEFILTER_CHANGE_DELAY = 5 * 60;
+/** Maximum number of compact filters that may be requested with one getcfilters. See BIP 157. */
+static constexpr uint32_t MAX_GETCFILTERS_SIZE = 1000;
/** Maximum number of cf hashes that may be requested with one getcfheaders. See BIP 157. */
static constexpr uint32_t MAX_GETCFHEADERS_SIZE = 2000;
@@ -827,7 +829,8 @@ void PeerLogicValidation::ReattemptInitialBroadcast(CScheduler& scheduler) const
}
}
- // schedule next run for 10-15 minutes in the future
+ // Schedule next run for 10-15 minutes in the future.
+ // We add randomness on every cycle to avoid the possibility of P2P fingerprinting.
const std::chrono::milliseconds delta = std::chrono::minutes{10} + GetRandMillis(std::chrono::minutes{5});
scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta);
}
@@ -1998,7 +2001,7 @@ void static ProcessOrphanTx(CConnman* connman, CTxMemPool& mempool, std::set<uin
* @param[out] filter_index The filter index, if the request can be serviced.
* @return True if the request can be serviced.
*/
-static bool PrepareBlockFilterRequest(CNode* pfrom, const CChainParams& chain_params,
+static bool PrepareBlockFilterRequest(CNode& pfrom, const CChainParams& chain_params,
BlockFilterType filter_type, uint32_t start_height,
const uint256& stop_hash, uint32_t max_height_diff,
const CBlockIndex*& stop_index,
@@ -2009,8 +2012,8 @@ static bool PrepareBlockFilterRequest(CNode* pfrom, const CChainParams& chain_pa
gArgs.GetBoolArg("-peerblockfilters", DEFAULT_PEERBLOCKFILTERS));
if (!supported_filter_type) {
LogPrint(BCLog::NET, "peer %d requested unsupported block filter type: %d\n",
- pfrom->GetId(), static_cast<uint8_t>(filter_type));
- pfrom->fDisconnect = true;
+ pfrom.GetId(), static_cast<uint8_t>(filter_type));
+ pfrom.fDisconnect = true;
return false;
}
@@ -2021,8 +2024,8 @@ static bool PrepareBlockFilterRequest(CNode* pfrom, const CChainParams& chain_pa
// Check that the stop block exists and the peer would be allowed to fetch it.
if (!stop_index || !BlockRequestAllowed(stop_index, chain_params.GetConsensus())) {
LogPrint(BCLog::NET, "peer %d requested invalid block hash: %s\n",
- pfrom->GetId(), stop_hash.ToString());
- pfrom->fDisconnect = true;
+ pfrom.GetId(), stop_hash.ToString());
+ pfrom.fDisconnect = true;
return false;
}
}
@@ -2031,14 +2034,14 @@ static bool PrepareBlockFilterRequest(CNode* pfrom, const CChainParams& chain_pa
if (start_height > stop_height) {
LogPrint(BCLog::NET, "peer %d sent invalid getcfilters/getcfheaders with " /* Continued */
"start height %d and stop height %d\n",
- pfrom->GetId(), start_height, stop_height);
- pfrom->fDisconnect = true;
+ pfrom.GetId(), start_height, stop_height);
+ pfrom.fDisconnect = true;
return false;
}
if (stop_height - start_height >= max_height_diff) {
LogPrint(BCLog::NET, "peer %d requested too many cfilters/cfheaders: %d / %d\n",
- pfrom->GetId(), stop_height - start_height + 1, max_height_diff);
- pfrom->fDisconnect = true;
+ pfrom.GetId(), stop_height - start_height + 1, max_height_diff);
+ pfrom.fDisconnect = true;
return false;
}
@@ -2052,6 +2055,49 @@ static bool PrepareBlockFilterRequest(CNode* pfrom, const CChainParams& chain_pa
}
/**
+ * Handle a cfilters request.
+ *
+ * May disconnect from the peer in the case of a bad request.
+ *
+ * @param[in] pfrom The peer that we received the request from
+ * @param[in] vRecv The raw message received
+ * @param[in] chain_params Chain parameters
+ * @param[in] connman Pointer to the connection manager
+ */
+static void ProcessGetCFilters(CNode& pfrom, CDataStream& vRecv, const CChainParams& chain_params,
+ CConnman& connman)
+{
+ uint8_t filter_type_ser;
+ uint32_t start_height;
+ uint256 stop_hash;
+
+ vRecv >> filter_type_ser >> start_height >> stop_hash;
+
+ const BlockFilterType filter_type = static_cast<BlockFilterType>(filter_type_ser);
+
+ const CBlockIndex* stop_index;
+ BlockFilterIndex* filter_index;
+ if (!PrepareBlockFilterRequest(pfrom, chain_params, filter_type, start_height, stop_hash,
+ MAX_GETCFILTERS_SIZE, stop_index, filter_index)) {
+ return;
+ }
+
+ std::vector<BlockFilter> filters;
+
+ if (!filter_index->LookupFilterRange(start_height, stop_index, filters)) {
+ LogPrint(BCLog::NET, "Failed to find block filter in index: filter_type=%s, start_height=%d, stop_hash=%s\n",
+ BlockFilterTypeName(filter_type), start_height, stop_hash.ToString());
+ return;
+ }
+
+ for (const auto& filter : filters) {
+ CSerializedNetMsg msg = CNetMsgMaker(pfrom.GetSendVersion())
+ .Make(NetMsgType::CFILTER, filter);
+ connman.PushMessage(&pfrom, std::move(msg));
+ }
+}
+
+/**
* Handle a cfheaders request.
*
* May disconnect from the peer in the case of a bad request.
@@ -2061,8 +2107,8 @@ static bool PrepareBlockFilterRequest(CNode* pfrom, const CChainParams& chain_pa
* @param[in] chain_params Chain parameters
* @param[in] connman Pointer to the connection manager
*/
-static void ProcessGetCFHeaders(CNode* pfrom, CDataStream& vRecv, const CChainParams& chain_params,
- CConnman* connman)
+static void ProcessGetCFHeaders(CNode& pfrom, CDataStream& vRecv, const CChainParams& chain_params,
+ CConnman& connman)
{
uint8_t filter_type_ser;
uint32_t start_height;
@@ -2097,13 +2143,13 @@ static void ProcessGetCFHeaders(CNode* pfrom, CDataStream& vRecv, const CChainPa
return;
}
- CSerializedNetMsg msg = CNetMsgMaker(pfrom->GetSendVersion())
+ CSerializedNetMsg msg = CNetMsgMaker(pfrom.GetSendVersion())
.Make(NetMsgType::CFHEADERS,
filter_type_ser,
stop_index->GetBlockHash(),
prev_header,
filter_hashes);
- connman->PushMessage(pfrom, std::move(msg));
+ connman.PushMessage(&pfrom, std::move(msg));
}
/**
@@ -2116,8 +2162,8 @@ static void ProcessGetCFHeaders(CNode* pfrom, CDataStream& vRecv, const CChainPa
* @param[in] chain_params Chain parameters
* @param[in] connman Pointer to the connection manager
*/
-static void ProcessGetCFCheckPt(CNode* pfrom, CDataStream& vRecv, const CChainParams& chain_params,
- CConnman* connman)
+static void ProcessGetCFCheckPt(CNode& pfrom, CDataStream& vRecv, const CChainParams& chain_params,
+ CConnman& connman)
{
uint8_t filter_type_ser;
uint256 stop_hash;
@@ -2149,12 +2195,12 @@ static void ProcessGetCFCheckPt(CNode* pfrom, CDataStream& vRecv, const CChainPa
}
}
- CSerializedNetMsg msg = CNetMsgMaker(pfrom->GetSendVersion())
+ CSerializedNetMsg msg = CNetMsgMaker(pfrom.GetSendVersion())
.Make(NetMsgType::CFCHECKPT,
filter_type_ser,
stop_index->GetBlockHash(),
headers);
- connman->PushMessage(pfrom, std::move(msg));
+ connman.PushMessage(&pfrom, std::move(msg));
}
bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, ChainstateManager& chainman, CTxMemPool& mempool, CConnman* connman, BanMan* banman, const std::atomic<bool>& interruptMsgProc)
@@ -3466,13 +3512,18 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec
return true;
}
+ if (msg_type == NetMsgType::GETCFILTERS) {
+ ProcessGetCFilters(*pfrom, vRecv, chainparams, *connman);
+ return true;
+ }
+
if (msg_type == NetMsgType::GETCFHEADERS) {
- ProcessGetCFHeaders(pfrom, vRecv, chainparams, connman);
+ ProcessGetCFHeaders(*pfrom, vRecv, chainparams, *connman);
return true;
}
if (msg_type == NetMsgType::GETCFCHECKPT) {
- ProcessGetCFCheckPt(pfrom, vRecv, chainparams, connman);
+ ProcessGetCFCheckPt(*pfrom, vRecv, chainparams, *connman);
return true;
}
diff --git a/src/protocol.cpp b/src/protocol.cpp
index 737baff36b..83a24b9d95 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -40,6 +40,8 @@ const char *SENDCMPCT="sendcmpct";
const char *CMPCTBLOCK="cmpctblock";
const char *GETBLOCKTXN="getblocktxn";
const char *BLOCKTXN="blocktxn";
+const char *GETCFILTERS="getcfilters";
+const char *CFILTER="cfilter";
const char *GETCFHEADERS="getcfheaders";
const char *CFHEADERS="cfheaders";
const char *GETCFCHECKPT="getcfcheckpt";
@@ -75,6 +77,8 @@ const static std::string allNetMessageTypes[] = {
NetMsgType::CMPCTBLOCK,
NetMsgType::GETBLOCKTXN,
NetMsgType::BLOCKTXN,
+ NetMsgType::GETCFILTERS,
+ NetMsgType::CFILTER,
NetMsgType::GETCFHEADERS,
NetMsgType::CFHEADERS,
NetMsgType::GETCFCHECKPT,
@@ -195,9 +199,15 @@ const std::vector<std::string> &getAllNetMessageTypes()
return allNetMessageTypesVec;
}
-std::string serviceFlagToStr(const uint64_t mask, const int bit)
+/**
+ * Convert a service flag (NODE_*) to a human readable string.
+ * It supports unknown service flags which will be returned as "UNKNOWN[...]".
+ * @param[in] bit the service flag is calculated as (1 << bit)
+ */
+static std::string serviceFlagToStr(size_t bit)
{
- switch (ServiceFlags(mask)) {
+ const uint64_t service_flag = 1ULL << bit;
+ switch ((ServiceFlags)service_flag) {
case NODE_NONE: abort(); // impossible
case NODE_NETWORK: return "NETWORK";
case NODE_GETUTXO: return "GETUTXO";
@@ -211,10 +221,23 @@ std::string serviceFlagToStr(const uint64_t mask, const int bit)
stream.imbue(std::locale::classic());
stream << "UNKNOWN[";
if (bit < 8) {
- stream << mask;
+ stream << service_flag;
} else {
stream << "2^" << bit;
}
stream << "]";
return stream.str();
}
+
+std::vector<std::string> serviceFlagsToStr(uint64_t flags)
+{
+ std::vector<std::string> str_flags;
+
+ for (size_t i = 0; i < sizeof(flags) * 8; ++i) {
+ if (flags & (1ULL << i)) {
+ str_flags.emplace_back(serviceFlagToStr(i));
+ }
+ }
+
+ return str_flags;
+}
diff --git a/src/protocol.h b/src/protocol.h
index c12bec9bf3..985f44640b 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -226,6 +226,17 @@ extern const char* GETBLOCKTXN;
*/
extern const char* BLOCKTXN;
/**
+ * getcfilters requests compact filters for a range of blocks.
+ * Only available with service bit NODE_COMPACT_FILTERS as described by
+ * BIP 157 & 158.
+ */
+extern const char* GETCFILTERS;
+/**
+ * cfilter is a response to a getcfilters request containing a single compact
+ * filter.
+ */
+extern const char* CFILTER;
+/**
* getcfheaders requests a compact filter header and the filter hashes for a
* range of blocks, which can then be used to reconstruct the filter headers
* for those blocks.
@@ -288,7 +299,12 @@ enum ServiceFlags : uint64_t {
// BIP process.
};
-std::string serviceFlagToStr(uint64_t mask, int bit);
+/**
+ * Convert service flags (a bitmask of NODE_*) to human readable strings.
+ * It supports unknown service flags which will be returned as "UNKNOWN[...]".
+ * @param[in] flags multiple NODE_* bitwise-OR-ed together
+ */
+std::vector<std::string> serviceFlagsToStr(uint64_t flags);
/**
* Gets the set of service flags which are "desirable" for a given peer.
diff --git a/src/psbt.h b/src/psbt.h
index af57994f3a..888e0fd119 100644
--- a/src/psbt.h
+++ b/src/psbt.h
@@ -41,7 +41,7 @@ static constexpr uint8_t PSBT_OUT_BIP32_DERIVATION = 0x02;
static constexpr uint8_t PSBT_SEPARATOR = 0x00;
// BIP 174 does not specify a maximum file size, but we set a limit anyway
-// to prevent reading a stream indefinately and running out of memory.
+// to prevent reading a stream indefinitely and running out of memory.
const std::streamsize MAX_FILE_SIZE_PSBT = 100000000; // 100 MiB
/** A structure for PSBTs which contain per-input information */
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index eeaa6ecfb2..f8cdb5df23 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -230,8 +230,6 @@ BitcoinApplication::~BitcoinApplication()
delete window;
window = nullptr;
- delete optionsModel;
- optionsModel = nullptr;
delete platformStyle;
platformStyle = nullptr;
}
@@ -245,7 +243,7 @@ void BitcoinApplication::createPaymentServer()
void BitcoinApplication::createOptionsModel(bool resetSettings)
{
- optionsModel = new OptionsModel(m_node, nullptr, resetSettings);
+ optionsModel = new OptionsModel(m_node, this, resetSettings);
}
void BitcoinApplication::createWindow(const NetworkStyle *networkStyle)
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index e78e400f07..ce44d4f3a5 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -755,12 +755,8 @@ QString formatServicesStr(quint64 mask)
{
QStringList strList;
- for (int i = 0; i < 64; i++) {
- uint64_t check = 1ull << i;
- if (mask & check)
- {
- strList.append(QString::fromStdString(serviceFlagToStr(mask, i)));
- }
+ for (const auto& flag : serviceFlagsToStr(mask)) {
+ strList.append(QString::fromStdString(flag));
}
if (strList.size())
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 0867ae8105..04eb1ae706 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -618,7 +618,7 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
return details;
}
case ConfirmedRole:
- return rec->status.countsForBalance;
+ return rec->status.status == TransactionStatus::Status::Confirming || rec->status.status == TransactionStatus::Status::Confirmed;
case FormattedAmountRole:
// Used for copy/export, so don't include separators
return formatTxAmount(rec, false, BitcoinUnits::separatorNever);
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index 66fbf978be..861d1c5f4a 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -258,7 +258,7 @@ void WalletView::gotoLoadPSBT()
TransactionError result = BroadcastTransaction(*clientModel->node().context(), tx, err_string, DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK(), /* relay */ true, /* wait_callback */ false);
if (result == TransactionError::OK) {
- Q_EMIT message(tr("Success"), tr("Broadcasted transaction sucessfully."), CClientUIInterface::MSG_INFORMATION | CClientUIInterface::MODAL);
+ Q_EMIT message(tr("Success"), tr("Broadcasted transaction successfully."), CClientUIInterface::MSG_INFORMATION | CClientUIInterface::MODAL);
} else {
Q_EMIT message(tr("Error"), QString::fromStdString(err_string), CClientUIInterface::MSG_ERROR);
}
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 4eb47d7b15..b0936cef5a 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -414,7 +414,7 @@ static std::vector<RPCResult> MempoolEntryDescription() { return {
RPCResult{RPCResult::Type::ARR, "spentby", "unconfirmed transactions spending outputs from this transaction",
{RPCResult{RPCResult::Type::STR_HEX, "transactionid", "child transaction id"}}},
RPCResult{RPCResult::Type::BOOL, "bip125-replaceable", "Whether this transaction could be replaced due to BIP125 (replace-by-fee)"},
- RPCResult{RPCResult::Type::BOOL, "unbroadcast", "Whether this transaction is currently unbroadcast (initial broadcast not yet confirmed)"},
+ RPCResult{RPCResult::Type::BOOL, "unbroadcast", "Whether this transaction is currently unbroadcast (initial broadcast not yet acknowledged by any peers)"},
};}
static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPoolEntry& e) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 3612f14bbf..3db0cb04ed 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -179,7 +179,7 @@ static bool getScriptFromDescriptor(const std::string& descriptor, CScript& scri
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Cannot derive script without private keys"));
}
- // Combo desriptors can have 2 or 4 scripts, so we can't just check scripts.size() == 1
+ // Combo descriptors can have 2 or 4 scripts, so we can't just check scripts.size() == 1
CHECK_NONFATAL(scripts.size() > 0 && scripts.size() <= 4);
if (scripts.size() == 1) {
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 99c649d15a..2a0079ac39 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -15,11 +15,15 @@
#include <boost/algorithm/string/split.hpp>
#include <boost/signals2/signal.hpp>
+#include <cassert>
#include <memory> // for unique_ptr
+#include <mutex>
#include <unordered_map>
static RecursiveMutex cs_rpcWarmup;
static std::atomic<bool> g_rpc_running{false};
+static std::once_flag g_rpc_interrupt_flag;
+static std::once_flag g_rpc_stop_flag;
static bool fRPCInWarmup GUARDED_BY(cs_rpcWarmup) = true;
static std::string rpcWarmupStatus GUARDED_BY(cs_rpcWarmup) = "RPC server started";
/* Timer-creating functions */
@@ -291,17 +295,24 @@ void StartRPC()
void InterruptRPC()
{
- LogPrint(BCLog::RPC, "Interrupting RPC\n");
- // Interrupt e.g. running longpolls
- g_rpc_running = false;
+ // This function could be called twice if the GUI has been started with -server=1.
+ std::call_once(g_rpc_interrupt_flag, []() {
+ LogPrint(BCLog::RPC, "Interrupting RPC\n");
+ // Interrupt e.g. running longpolls
+ g_rpc_running = false;
+ });
}
void StopRPC()
{
- LogPrint(BCLog::RPC, "Stopping RPC\n");
- WITH_LOCK(g_deadline_timers_mutex, deadlineTimers.clear());
- DeleteAuthCookie();
- g_rpcSignals.Stopped();
+ // This function could be called twice if the GUI has been started with -server=1.
+ assert(!g_rpc_running);
+ std::call_once(g_rpc_stop_flag, []() {
+ LogPrint(BCLog::RPC, "Stopping RPC\n");
+ WITH_LOCK(g_deadline_timers_mutex, deadlineTimers.clear());
+ DeleteAuthCookie();
+ g_rpcSignals.Stopped();
+ });
}
bool IsRPCRunning()
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index 0e13d8dfce..39bf05fbbd 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -841,14 +841,10 @@ std::vector<CScript> EvalDescriptorStringOrObject(const UniValue& scanobject, Fl
UniValue GetServicesNames(ServiceFlags services)
{
- const uint64_t services_n = services;
UniValue servicesNames(UniValue::VARR);
- for (int i = 0; i < 64; ++i) {
- const uint64_t mask = 1ull << i;
- if (services_n & mask) {
- servicesNames.push_back(serviceFlagToStr(mask, i));
- }
+ for (const auto& flag : serviceFlagsToStr(services)) {
+ servicesNames.push_back(flag);
}
return servicesNames;
diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp
index e0c4ad7eb7..933cf9049d 100644
--- a/src/test/fuzz/script.cpp
+++ b/src/test/fuzz/script.cpp
@@ -11,6 +11,7 @@
#include <script/descriptor.h>
#include <script/interpreter.h>
#include <script/script.h>
+#include <script/script_error.h>
#include <script/sign.h>
#include <script/signingprovider.h>
#include <script/standard.h>
@@ -21,6 +22,8 @@
#include <univalue.h>
#include <util/memory.h>
+#include <algorithm>
+#include <cassert>
#include <cstdint>
#include <optional>
#include <string>
@@ -124,4 +127,40 @@ void test_one_input(const std::vector<uint8_t>& buffer)
wit.SetNull();
}
}
+
+ (void)GetOpName(ConsumeOpcodeType(fuzzed_data_provider));
+ (void)ScriptErrorString(static_cast<ScriptError>(fuzzed_data_provider.ConsumeIntegralInRange<int>(0, SCRIPT_ERR_ERROR_COUNT)));
+
+ {
+ const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ CScript append_script{bytes.begin(), bytes.end()};
+ append_script << fuzzed_data_provider.ConsumeIntegral<int64_t>();
+ append_script << ConsumeOpcodeType(fuzzed_data_provider);
+ append_script << CScriptNum{fuzzed_data_provider.ConsumeIntegral<int64_t>()};
+ append_script << ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ }
+
+ {
+ WitnessUnknown witness_unknown_1{};
+ witness_unknown_1.version = fuzzed_data_provider.ConsumeIntegral<int>();
+ const std::vector<uint8_t> witness_unknown_program_1 = fuzzed_data_provider.ConsumeBytes<uint8_t>(40);
+ witness_unknown_1.length = witness_unknown_program_1.size();
+ std::copy(witness_unknown_program_1.begin(), witness_unknown_program_1.end(), witness_unknown_1.program);
+
+ WitnessUnknown witness_unknown_2{};
+ witness_unknown_2.version = fuzzed_data_provider.ConsumeIntegral<int>();
+ const std::vector<uint8_t> witness_unknown_program_2 = fuzzed_data_provider.ConsumeBytes<uint8_t>(40);
+ witness_unknown_2.length = witness_unknown_program_2.size();
+ std::copy(witness_unknown_program_2.begin(), witness_unknown_program_2.end(), witness_unknown_2.program);
+
+ (void)(witness_unknown_1 == witness_unknown_2);
+ (void)(witness_unknown_1 < witness_unknown_2);
+ }
+
+ {
+ const CTxDestination tx_destination_1 = ConsumeTxDestination(fuzzed_data_provider);
+ const CTxDestination tx_destination_2 = ConsumeTxDestination(fuzzed_data_provider);
+ (void)(tx_destination_1 == tx_destination_2);
+ (void)(tx_destination_1 < tx_destination_2);
+ }
}
diff --git a/src/test/fuzz/script_bitcoin_consensus.cpp b/src/test/fuzz/script_bitcoin_consensus.cpp
new file mode 100644
index 0000000000..22f4b4f44a
--- /dev/null
+++ b/src/test/fuzz/script_bitcoin_consensus.cpp
@@ -0,0 +1,31 @@
+// 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 <script/bitcoinconsensus.h>
+#include <script/interpreter.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+ const std::vector<uint8_t> random_bytes_1 = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ const std::vector<uint8_t> random_bytes_2 = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ const CAmount money = ConsumeMoney(fuzzed_data_provider);
+ bitcoinconsensus_error err;
+ bitcoinconsensus_error* err_p = fuzzed_data_provider.ConsumeBool() ? &err : nullptr;
+ const unsigned int n_in = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
+ const unsigned int flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
+ assert(bitcoinconsensus_version() == BITCOINCONSENSUS_API_VER);
+ if ((flags & SCRIPT_VERIFY_WITNESS) != 0 && (flags & SCRIPT_VERIFY_P2SH) == 0) {
+ return;
+ }
+ (void)bitcoinconsensus_verify_script(random_bytes_1.data(), random_bytes_1.size(), random_bytes_2.data(), random_bytes_2.size(), n_in, flags, err_p);
+ (void)bitcoinconsensus_verify_script_with_amount(random_bytes_1.data(), random_bytes_1.size(), money, random_bytes_2.data(), random_bytes_2.size(), n_in, flags, err_p);
+}
diff --git a/src/test/fuzz/script_descriptor_cache.cpp b/src/test/fuzz/script_descriptor_cache.cpp
new file mode 100644
index 0000000000..4bfe61cec7
--- /dev/null
+++ b/src/test/fuzz/script_descriptor_cache.cpp
@@ -0,0 +1,42 @@
+// 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 <optional.h>
+#include <pubkey.h>
+#include <script/descriptor.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+ DescriptorCache descriptor_cache;
+ while (fuzzed_data_provider.ConsumeBool()) {
+ const std::vector<uint8_t> code = fuzzed_data_provider.ConsumeBytes<uint8_t>(BIP32_EXTKEY_SIZE);
+ if (code.size() == BIP32_EXTKEY_SIZE) {
+ CExtPubKey xpub;
+ xpub.Decode(code.data());
+ const uint32_t key_exp_pos = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
+ CExtPubKey xpub_fetched;
+ if (fuzzed_data_provider.ConsumeBool()) {
+ (void)descriptor_cache.GetCachedParentExtPubKey(key_exp_pos, xpub_fetched);
+ descriptor_cache.CacheParentExtPubKey(key_exp_pos, xpub);
+ assert(descriptor_cache.GetCachedParentExtPubKey(key_exp_pos, xpub_fetched));
+ } else {
+ const uint32_t der_index = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
+ (void)descriptor_cache.GetCachedDerivedExtPubKey(key_exp_pos, der_index, xpub_fetched);
+ descriptor_cache.CacheDerivedExtPubKey(key_exp_pos, der_index, xpub);
+ assert(descriptor_cache.GetCachedDerivedExtPubKey(key_exp_pos, der_index, xpub_fetched));
+ }
+ assert(xpub == xpub_fetched);
+ }
+ (void)descriptor_cache.GetCachedParentExtPubKeys();
+ (void)descriptor_cache.GetCachedDerivedExtPubKeys();
+ }
+}
diff --git a/src/test/fuzz/script_interpreter.cpp b/src/test/fuzz/script_interpreter.cpp
new file mode 100644
index 0000000000..26d5732f24
--- /dev/null
+++ b/src/test/fuzz/script_interpreter.cpp
@@ -0,0 +1,41 @@
+// 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 <primitives/transaction.h>
+#include <script/interpreter.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <cstdint>
+#include <optional>
+#include <string>
+#include <vector>
+
+bool CastToBool(const std::vector<unsigned char>& vch);
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+ {
+ const CScript script_code = ConsumeScript(fuzzed_data_provider);
+ const std::optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
+ if (mtx) {
+ const CTransaction tx_to{*mtx};
+ const unsigned int in = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
+ if (in < tx_to.vin.size()) {
+ (void)SignatureHash(script_code, tx_to, in, fuzzed_data_provider.ConsumeIntegral<int>(), ConsumeMoney(fuzzed_data_provider), fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0}), nullptr);
+ const std::optional<CMutableTransaction> mtx_precomputed = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
+ if (mtx_precomputed) {
+ const CTransaction tx_precomputed{*mtx_precomputed};
+ const PrecomputedTransactionData precomputed_transaction_data{tx_precomputed};
+ (void)SignatureHash(script_code, tx_to, in, fuzzed_data_provider.ConsumeIntegral<int>(), ConsumeMoney(fuzzed_data_provider), fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0}), &precomputed_transaction_data);
+ }
+ }
+ }
+ }
+ {
+ (void)CastToBool(ConsumeRandomLengthByteVector(fuzzed_data_provider));
+ }
+}
diff --git a/src/test/fuzz/script_sigcache.cpp b/src/test/fuzz/script_sigcache.cpp
new file mode 100644
index 0000000000..434a47b702
--- /dev/null
+++ b/src/test/fuzz/script_sigcache.cpp
@@ -0,0 +1,45 @@
+// 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 <key.h>
+#include <pubkey.h>
+#include <script/sigcache.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <cstdint>
+#include <optional>
+#include <string>
+#include <vector>
+
+void initialize()
+{
+ static const ECCVerifyHandle ecc_verify_handle;
+ ECC_Start();
+ SelectParams(CBaseChainParams::REGTEST);
+ InitSignatureCache();
+}
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+
+ const std::optional<CMutableTransaction> mutable_transaction = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
+ const CTransaction tx = mutable_transaction ? CTransaction{*mutable_transaction} : CTransaction{};
+ const unsigned int n_in = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
+ const CAmount amount = ConsumeMoney(fuzzed_data_provider);
+ const bool store = fuzzed_data_provider.ConsumeBool();
+ PrecomputedTransactionData tx_data;
+ CachingTransactionSignatureChecker caching_transaction_signature_checker{mutable_transaction ? &tx : nullptr, n_in, amount, store, tx_data};
+ const std::optional<CPubKey> pub_key = ConsumeDeserializable<CPubKey>(fuzzed_data_provider);
+ if (pub_key) {
+ const std::vector<uint8_t> random_bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ if (!random_bytes.empty()) {
+ (void)caching_transaction_signature_checker.VerifySignature(random_bytes, *pub_key, ConsumeUInt256(fuzzed_data_provider));
+ }
+ }
+}
diff --git a/src/test/fuzz/script_sign.cpp b/src/test/fuzz/script_sign.cpp
new file mode 100644
index 0000000000..c626f950e7
--- /dev/null
+++ b/src/test/fuzz/script_sign.cpp
@@ -0,0 +1,149 @@
+// 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 <key.h>
+#include <pubkey.h>
+#include <script/keyorigin.h>
+#include <script/sign.h>
+#include <script/signingprovider.h>
+#include <streams.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <cassert>
+#include <cstdint>
+#include <iostream>
+#include <map>
+#include <optional>
+#include <string>
+#include <vector>
+
+void initialize()
+{
+ static const ECCVerifyHandle ecc_verify_handle;
+ ECC_Start();
+ SelectParams(CBaseChainParams::REGTEST);
+}
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+ const std::vector<uint8_t> key = ConsumeRandomLengthByteVector(fuzzed_data_provider, 128);
+
+ {
+ CDataStream random_data_stream = ConsumeDataStream(fuzzed_data_provider);
+ std::map<CPubKey, KeyOriginInfo> hd_keypaths;
+ try {
+ DeserializeHDKeypaths(random_data_stream, key, hd_keypaths);
+ } catch (const std::ios_base::failure&) {
+ }
+ CDataStream serialized{SER_NETWORK, PROTOCOL_VERSION};
+ SerializeHDKeypaths(serialized, hd_keypaths, fuzzed_data_provider.ConsumeIntegral<uint8_t>());
+ }
+
+ {
+ std::map<CPubKey, KeyOriginInfo> hd_keypaths;
+ while (fuzzed_data_provider.ConsumeBool()) {
+ const std::optional<CPubKey> pub_key = ConsumeDeserializable<CPubKey>(fuzzed_data_provider);
+ if (!pub_key) {
+ break;
+ }
+ const std::optional<KeyOriginInfo> key_origin_info = ConsumeDeserializable<KeyOriginInfo>(fuzzed_data_provider);
+ if (!key_origin_info) {
+ break;
+ }
+ hd_keypaths[*pub_key] = *key_origin_info;
+ }
+ CDataStream serialized{SER_NETWORK, PROTOCOL_VERSION};
+ try {
+ SerializeHDKeypaths(serialized, hd_keypaths, fuzzed_data_provider.ConsumeIntegral<uint8_t>());
+ } catch (const std::ios_base::failure&) {
+ }
+ std::map<CPubKey, KeyOriginInfo> deserialized_hd_keypaths;
+ try {
+ DeserializeHDKeypaths(serialized, key, hd_keypaths);
+ } catch (const std::ios_base::failure&) {
+ }
+ assert(hd_keypaths.size() >= deserialized_hd_keypaths.size());
+ }
+
+ {
+ SignatureData signature_data_1{ConsumeScript(fuzzed_data_provider)};
+ SignatureData signature_data_2{ConsumeScript(fuzzed_data_provider)};
+ signature_data_1.MergeSignatureData(signature_data_2);
+ }
+
+ FillableSigningProvider provider;
+ CKey k;
+ const std::vector<uint8_t> key_data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ k.Set(key_data.begin(), key_data.end(), fuzzed_data_provider.ConsumeBool());
+ if (k.IsValid()) {
+ provider.AddKey(k);
+ }
+
+ {
+ const std::optional<CMutableTransaction> mutable_transaction = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
+ const std::optional<CTxOut> tx_out = ConsumeDeserializable<CTxOut>(fuzzed_data_provider);
+ const unsigned int n_in = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
+ if (mutable_transaction && tx_out && mutable_transaction->vin.size() > n_in) {
+ SignatureData signature_data_1 = DataFromTransaction(*mutable_transaction, n_in, *tx_out);
+ CTxIn input;
+ UpdateInput(input, signature_data_1);
+ const CScript script = ConsumeScript(fuzzed_data_provider);
+ SignatureData signature_data_2{script};
+ signature_data_1.MergeSignatureData(signature_data_2);
+ }
+ if (mutable_transaction) {
+ CTransaction tx_from{*mutable_transaction};
+ CMutableTransaction tx_to;
+ const std::optional<CMutableTransaction> opt_tx_to = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
+ if (opt_tx_to) {
+ tx_to = *opt_tx_to;
+ }
+ CMutableTransaction script_tx_to = tx_to;
+ CMutableTransaction sign_transaction_tx_to = tx_to;
+ if (n_in < tx_to.vin.size() && tx_to.vin[n_in].prevout.n < tx_from.vout.size()) {
+ (void)SignSignature(provider, tx_from, tx_to, n_in, fuzzed_data_provider.ConsumeIntegral<int>());
+ }
+ if (n_in < script_tx_to.vin.size()) {
+ (void)SignSignature(provider, ConsumeScript(fuzzed_data_provider), script_tx_to, n_in, ConsumeMoney(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<int>());
+ MutableTransactionSignatureCreator signature_creator{&tx_to, n_in, ConsumeMoney(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<int>()};
+ std::vector<unsigned char> vch_sig;
+ CKeyID address;
+ if (fuzzed_data_provider.ConsumeBool()) {
+ if (k.IsValid()) {
+ address = k.GetPubKey().GetID();
+ }
+ } else {
+ address = CKeyID{ConsumeUInt160(fuzzed_data_provider)};
+ }
+ (void)signature_creator.CreateSig(provider, vch_sig, address, ConsumeScript(fuzzed_data_provider), fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0}));
+ }
+ std::map<COutPoint, Coin> coins;
+ while (fuzzed_data_provider.ConsumeBool()) {
+ const std::optional<COutPoint> outpoint = ConsumeDeserializable<COutPoint>(fuzzed_data_provider);
+ if (!outpoint) {
+ break;
+ }
+ const std::optional<Coin> coin = ConsumeDeserializable<Coin>(fuzzed_data_provider);
+ if (!coin) {
+ break;
+ }
+ coins[*outpoint] = *coin;
+ }
+ std::map<int, std::string> input_errors;
+ (void)SignTransaction(sign_transaction_tx_to, &provider, coins, fuzzed_data_provider.ConsumeIntegral<int>(), input_errors);
+ }
+ }
+
+ {
+ SignatureData signature_data_1;
+ (void)ProduceSignature(provider, DUMMY_SIGNATURE_CREATOR, ConsumeScript(fuzzed_data_provider), signature_data_1);
+ SignatureData signature_data_2;
+ (void)ProduceSignature(provider, DUMMY_MAXIMUM_SIGNATURE_CREATOR, ConsumeScript(fuzzed_data_provider), signature_data_2);
+ }
+}
diff --git a/src/test/fuzz/string.cpp b/src/test/fuzz/string.cpp
index 50984b1aef..271062dc95 100644
--- a/src/test/fuzz/string.cpp
+++ b/src/test/fuzz/string.cpp
@@ -12,6 +12,7 @@
#include <rpc/server.h>
#include <rpc/util.h>
#include <script/descriptor.h>
+#include <script/script.h>
#include <serialize.h>
#include <streams.h>
#include <test/fuzz/FuzzedDataProvider.h>
@@ -89,6 +90,10 @@ void test_one_input(const std::vector<uint8_t>& buffer)
(void)urlDecode(random_string_1);
(void)ValidAsCString(random_string_1);
(void)_(random_string_1.c_str());
+ try {
+ throw scriptnum_error{random_string_1};
+ } catch (const std::runtime_error&) {
+ }
{
CDataStream data_stream{SER_NETWORK, INIT_PROTO_VERSION};
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index 9d0fb02128..f26878a704 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -12,6 +12,7 @@
#include <consensus/consensus.h>
#include <primitives/transaction.h>
#include <script/script.h>
+#include <script/standard.h>
#include <serialize.h>
#include <streams.h>
#include <test/fuzz/FuzzedDataProvider.h>
@@ -20,6 +21,7 @@
#include <uint256.h>
#include <version.h>
+#include <algorithm>
#include <cstdint>
#include <optional>
#include <string>
@@ -31,6 +33,11 @@ NODISCARD inline std::vector<uint8_t> ConsumeRandomLengthByteVector(FuzzedDataPr
return {s.begin(), s.end()};
}
+NODISCARD inline CDataStream ConsumeDataStream(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
+{
+ return {ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length), SER_NETWORK, INIT_PROTO_VERSION};
+}
+
NODISCARD inline std::vector<std::string> ConsumeRandomLengthStringVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_vector_size = 16, const size_t max_string_length = 16) noexcept
{
const size_t n_elements = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, max_vector_size);
@@ -87,10 +94,19 @@ NODISCARD inline CScriptNum ConsumeScriptNum(FuzzedDataProvider& fuzzed_data_pro
return CScriptNum{fuzzed_data_provider.ConsumeIntegral<int64_t>()};
}
+NODISCARD inline uint160 ConsumeUInt160(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ const std::vector<uint8_t> v160 = fuzzed_data_provider.ConsumeBytes<uint8_t>(160 / 8);
+ if (v160.size() != 160 / 8) {
+ return {};
+ }
+ return uint160{v160};
+}
+
NODISCARD inline uint256 ConsumeUInt256(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
- const std::vector<unsigned char> v256 = fuzzed_data_provider.ConsumeBytes<unsigned char>(sizeof(uint256));
- if (v256.size() != sizeof(uint256)) {
+ const std::vector<uint8_t> v256 = fuzzed_data_provider.ConsumeBytes<uint8_t>(256 / 8);
+ if (v256.size() != 256 / 8) {
return {};
}
return uint256{v256};
@@ -116,6 +132,43 @@ NODISCARD inline CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzze
return CTxMemPoolEntry{MakeTransactionRef(tx), fee, time, entry_height, spends_coinbase, sig_op_cost, {}};
}
+NODISCARD inline CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ CTxDestination tx_destination;
+ switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 5)) {
+ case 0: {
+ tx_destination = CNoDestination{};
+ break;
+ }
+ case 1: {
+ tx_destination = PKHash{ConsumeUInt160(fuzzed_data_provider)};
+ break;
+ }
+ case 2: {
+ tx_destination = ScriptHash{ConsumeUInt160(fuzzed_data_provider)};
+ break;
+ }
+ case 3: {
+ tx_destination = WitnessV0ScriptHash{ConsumeUInt256(fuzzed_data_provider)};
+ break;
+ }
+ case 4: {
+ tx_destination = WitnessV0KeyHash{ConsumeUInt160(fuzzed_data_provider)};
+ break;
+ }
+ case 5: {
+ WitnessUnknown witness_unknown{};
+ witness_unknown.version = fuzzed_data_provider.ConsumeIntegral<int>();
+ const std::vector<uint8_t> witness_unknown_program_1 = fuzzed_data_provider.ConsumeBytes<uint8_t>(40);
+ witness_unknown.length = witness_unknown_program_1.size();
+ std::copy(witness_unknown_program_1.begin(), witness_unknown_program_1.end(), witness_unknown.program);
+ tx_destination = witness_unknown;
+ break;
+ }
+ }
+ return tx_destination;
+}
+
template <typename T>
NODISCARD bool MultiplicationOverflow(const T i, const T j) noexcept
{
diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp
index 512e48f8e5..45c9b90ee9 100644
--- a/src/test/getarg_tests.cpp
+++ b/src/test/getarg_tests.cpp
@@ -13,9 +13,18 @@
#include <boost/algorithm/string.hpp>
#include <boost/test/unit_test.hpp>
-BOOST_FIXTURE_TEST_SUITE(getarg_tests, BasicTestingSetup)
+namespace getarg_tests{
+ class LocalTestingSetup : BasicTestingSetup {
+ protected:
+ void SetupArgs(const std::vector<std::pair<std::string, unsigned int>>& args);
+ void ResetArgs(const std::string& strArg);
+ ArgsManager m_args;
+ };
+}
+
+BOOST_FIXTURE_TEST_SUITE(getarg_tests, LocalTestingSetup)
-static void ResetArgs(const std::string& strArg)
+void LocalTestingSetup :: ResetArgs(const std::string& strArg)
{
std::vector<std::string> vecArg;
if (strArg.size())
@@ -30,14 +39,14 @@ static void ResetArgs(const std::string& strArg)
vecChar.push_back(s.c_str());
std::string error;
- BOOST_CHECK(gArgs.ParseParameters(vecChar.size(), vecChar.data(), error));
+ BOOST_CHECK(m_args.ParseParameters(vecChar.size(), vecChar.data(), error));
}
-static void SetupArgs(const std::vector<std::pair<std::string, unsigned int>>& args)
+void LocalTestingSetup :: SetupArgs(const std::vector<std::pair<std::string, unsigned int>>& args)
{
- gArgs.ClearArgs();
+ m_args.ClearArgs();
for (const auto& arg : args) {
- gArgs.AddArg(arg.first, "", arg.second, OptionsCategory::OPTIONS);
+ m_args.AddArg(arg.first, "", arg.second, OptionsCategory::OPTIONS);
}
}
@@ -46,52 +55,52 @@ BOOST_AUTO_TEST_CASE(boolarg)
const auto foo = std::make_pair("-foo", ArgsManager::ALLOW_ANY);
SetupArgs({foo});
ResetArgs("-foo");
- BOOST_CHECK(gArgs.GetBoolArg("-foo", false));
- BOOST_CHECK(gArgs.GetBoolArg("-foo", true));
+ BOOST_CHECK(m_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(m_args.GetBoolArg("-foo", true));
- BOOST_CHECK(!gArgs.GetBoolArg("-fo", false));
- BOOST_CHECK(gArgs.GetBoolArg("-fo", true));
+ BOOST_CHECK(!m_args.GetBoolArg("-fo", false));
+ BOOST_CHECK(m_args.GetBoolArg("-fo", true));
- BOOST_CHECK(!gArgs.GetBoolArg("-fooo", false));
- BOOST_CHECK(gArgs.GetBoolArg("-fooo", true));
+ BOOST_CHECK(!m_args.GetBoolArg("-fooo", false));
+ BOOST_CHECK(m_args.GetBoolArg("-fooo", true));
ResetArgs("-foo=0");
- BOOST_CHECK(!gArgs.GetBoolArg("-foo", false));
- BOOST_CHECK(!gArgs.GetBoolArg("-foo", true));
+ BOOST_CHECK(!m_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(!m_args.GetBoolArg("-foo", true));
ResetArgs("-foo=1");
- BOOST_CHECK(gArgs.GetBoolArg("-foo", false));
- BOOST_CHECK(gArgs.GetBoolArg("-foo", true));
+ BOOST_CHECK(m_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(m_args.GetBoolArg("-foo", true));
// New 0.6 feature: auto-map -nosomething to !-something:
ResetArgs("-nofoo");
- BOOST_CHECK(!gArgs.GetBoolArg("-foo", false));
- BOOST_CHECK(!gArgs.GetBoolArg("-foo", true));
+ BOOST_CHECK(!m_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(!m_args.GetBoolArg("-foo", true));
ResetArgs("-nofoo=1");
- BOOST_CHECK(!gArgs.GetBoolArg("-foo", false));
- BOOST_CHECK(!gArgs.GetBoolArg("-foo", true));
+ BOOST_CHECK(!m_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(!m_args.GetBoolArg("-foo", true));
ResetArgs("-foo -nofoo"); // -nofoo should win
- BOOST_CHECK(!gArgs.GetBoolArg("-foo", false));
- BOOST_CHECK(!gArgs.GetBoolArg("-foo", true));
+ BOOST_CHECK(!m_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(!m_args.GetBoolArg("-foo", true));
ResetArgs("-foo=1 -nofoo=1"); // -nofoo should win
- BOOST_CHECK(!gArgs.GetBoolArg("-foo", false));
- BOOST_CHECK(!gArgs.GetBoolArg("-foo", true));
+ BOOST_CHECK(!m_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(!m_args.GetBoolArg("-foo", true));
ResetArgs("-foo=0 -nofoo=0"); // -nofoo=0 should win
- BOOST_CHECK(gArgs.GetBoolArg("-foo", false));
- BOOST_CHECK(gArgs.GetBoolArg("-foo", true));
+ BOOST_CHECK(m_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(m_args.GetBoolArg("-foo", true));
// New 0.6 feature: treat -- same as -:
ResetArgs("--foo=1");
- BOOST_CHECK(gArgs.GetBoolArg("-foo", false));
- BOOST_CHECK(gArgs.GetBoolArg("-foo", true));
+ BOOST_CHECK(m_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(m_args.GetBoolArg("-foo", true));
ResetArgs("--nofoo=1");
- BOOST_CHECK(!gArgs.GetBoolArg("-foo", false));
- BOOST_CHECK(!gArgs.GetBoolArg("-foo", true));
+ BOOST_CHECK(!m_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(!m_args.GetBoolArg("-foo", true));
}
@@ -101,24 +110,24 @@ BOOST_AUTO_TEST_CASE(stringarg)
const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY);
SetupArgs({foo, bar});
ResetArgs("");
- BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", ""), "");
- BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", "eleven"), "eleven");
+ BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), "");
+ BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), "eleven");
ResetArgs("-foo -bar");
- BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", ""), "");
- BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", "eleven"), "");
+ BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), "");
+ BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), "");
ResetArgs("-foo=");
- BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", ""), "");
- BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", "eleven"), "");
+ BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), "");
+ BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), "");
ResetArgs("-foo=11");
- BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", ""), "11");
- BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", "eleven"), "11");
+ BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), "11");
+ BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), "11");
ResetArgs("-foo=eleven");
- BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", ""), "eleven");
- BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", "eleven"), "eleven");
+ BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), "eleven");
+ BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), "eleven");
}
@@ -128,20 +137,20 @@ BOOST_AUTO_TEST_CASE(intarg)
const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY);
SetupArgs({foo, bar});
ResetArgs("");
- BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", 11), 11);
- BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", 0), 0);
+ BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 11), 11);
+ BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 0), 0);
ResetArgs("-foo -bar");
- BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", 11), 0);
- BOOST_CHECK_EQUAL(gArgs.GetArg("-bar", 11), 0);
+ BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 11), 0);
+ BOOST_CHECK_EQUAL(m_args.GetArg("-bar", 11), 0);
ResetArgs("-foo=11 -bar=12");
- BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", 0), 11);
- BOOST_CHECK_EQUAL(gArgs.GetArg("-bar", 11), 12);
+ BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 0), 11);
+ BOOST_CHECK_EQUAL(m_args.GetArg("-bar", 11), 12);
ResetArgs("-foo=NaN -bar=NotANumber");
- BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", 1), 0);
- BOOST_CHECK_EQUAL(gArgs.GetArg("-bar", 11), 0);
+ BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 1), 0);
+ BOOST_CHECK_EQUAL(m_args.GetArg("-bar", 11), 0);
}
BOOST_AUTO_TEST_CASE(doubledash)
@@ -150,11 +159,11 @@ BOOST_AUTO_TEST_CASE(doubledash)
const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY);
SetupArgs({foo, bar});
ResetArgs("--foo");
- BOOST_CHECK_EQUAL(gArgs.GetBoolArg("-foo", false), true);
+ BOOST_CHECK_EQUAL(m_args.GetBoolArg("-foo", false), true);
ResetArgs("--foo=verbose --bar=1");
- BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", ""), "verbose");
- BOOST_CHECK_EQUAL(gArgs.GetArg("-bar", 0), 1);
+ BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), "verbose");
+ BOOST_CHECK_EQUAL(m_args.GetArg("-bar", 0), 1);
}
BOOST_AUTO_TEST_CASE(boolargno)
@@ -163,24 +172,24 @@ BOOST_AUTO_TEST_CASE(boolargno)
const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY);
SetupArgs({foo, bar});
ResetArgs("-nofoo");
- BOOST_CHECK(!gArgs.GetBoolArg("-foo", true));
- BOOST_CHECK(!gArgs.GetBoolArg("-foo", false));
+ BOOST_CHECK(!m_args.GetBoolArg("-foo", true));
+ BOOST_CHECK(!m_args.GetBoolArg("-foo", false));
ResetArgs("-nofoo=1");
- BOOST_CHECK(!gArgs.GetBoolArg("-foo", true));
- BOOST_CHECK(!gArgs.GetBoolArg("-foo", false));
+ BOOST_CHECK(!m_args.GetBoolArg("-foo", true));
+ BOOST_CHECK(!m_args.GetBoolArg("-foo", false));
ResetArgs("-nofoo=0");
- BOOST_CHECK(gArgs.GetBoolArg("-foo", true));
- BOOST_CHECK(gArgs.GetBoolArg("-foo", false));
+ BOOST_CHECK(m_args.GetBoolArg("-foo", true));
+ BOOST_CHECK(m_args.GetBoolArg("-foo", false));
ResetArgs("-foo --nofoo"); // --nofoo should win
- BOOST_CHECK(!gArgs.GetBoolArg("-foo", true));
- BOOST_CHECK(!gArgs.GetBoolArg("-foo", false));
+ BOOST_CHECK(!m_args.GetBoolArg("-foo", true));
+ BOOST_CHECK(!m_args.GetBoolArg("-foo", false));
ResetArgs("-nofoo -foo"); // foo always wins:
- BOOST_CHECK(gArgs.GetBoolArg("-foo", true));
- BOOST_CHECK(gArgs.GetBoolArg("-foo", false));
+ BOOST_CHECK(m_args.GetBoolArg("-foo", true));
+ BOOST_CHECK(m_args.GetBoolArg("-foo", false));
}
BOOST_AUTO_TEST_CASE(logargs)
@@ -200,7 +209,7 @@ BOOST_AUTO_TEST_CASE(logargs)
});
// Log the arguments
- gArgs.LogArgs();
+ m_args.LogArgs();
LogInstance().DeleteCallback(print_connection);
// Check that what should appear does, and what shouldn't doesn't.
diff --git a/src/test/raii_event_tests.cpp b/src/test/raii_event_tests.cpp
index 04bf7c20c1..8c2712f764 100644
--- a/src/test/raii_event_tests.cpp
+++ b/src/test/raii_event_tests.cpp
@@ -4,9 +4,6 @@
#include <event2/event.h>
-#ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED
-// It would probably be ideal to define dummy test(s) that report skipped, but boost::test doesn't seem to make that practical (at least not in versions available with common distros)
-
#include <map>
#include <stdlib.h>
@@ -16,6 +13,10 @@
#include <boost/test/unit_test.hpp>
+BOOST_FIXTURE_TEST_SUITE(raii_event_tests, BasicTestingSetup)
+
+#ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED
+
static std::map<void*, short> tags;
static std::map<void*, uint16_t> orders;
static uint16_t tagSequence = 0;
@@ -34,8 +35,6 @@ static void tag_free(void* mem) {
free(mem);
}
-BOOST_FIXTURE_TEST_SUITE(raii_event_tests, BasicTestingSetup)
-
BOOST_AUTO_TEST_CASE(raii_event_creation)
{
event_set_mem_functions(tag_malloc, realloc, tag_free);
@@ -87,6 +86,14 @@ BOOST_AUTO_TEST_CASE(raii_event_order)
event_set_mem_functions(malloc, realloc, free);
}
-BOOST_AUTO_TEST_SUITE_END()
+#else
+
+BOOST_AUTO_TEST_CASE(raii_event_tests_SKIPPED)
+{
+ // It would probably be ideal to report skipped, but boost::test doesn't seem to make that practical (at least not in versions available with common distros)
+ BOOST_TEST_MESSAGE("Skipping raii_event_tess: libevent doesn't support event_set_mem_functions");
+}
#endif // EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/txmempool.h b/src/txmempool.h
index 4568eb928d..583f7614b7 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -704,7 +704,7 @@ public:
/** Adds a transaction to the unbroadcast set */
void AddUnbroadcastTx(const uint256& txid) {
LOCK(cs);
- /** Sanity Check: the transaction should also be in the mempool */
+ // Sanity Check: the transaction should also be in the mempool
if (exists(txid)) {
m_unbroadcast_txids.insert(txid);
}
@@ -714,12 +714,12 @@ public:
void RemoveUnbroadcastTx(const uint256& txid, const bool unchecked = false);
/** Returns transactions in unbroadcast set */
- const std::set<uint256> GetUnbroadcastTxs() const {
+ std::set<uint256> GetUnbroadcastTxs() const {
LOCK(cs);
return m_unbroadcast_txids;
}
- // Returns if a txid is in the unbroadcast set
+ /** Returns whether a txid is in the unbroadcast set */
bool IsUnbroadcastTx(const uint256& txid) const {
LOCK(cs);
return (m_unbroadcast_txids.count(txid) != 0);
diff --git a/src/validation.cpp b/src/validation.cpp
index dbdf5028fd..396fc0a1b5 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -5067,12 +5067,18 @@ bool LoadMempool(CTxMemPool& pool)
pool.PrioritiseTransaction(i.first, i.second);
}
- std::set<uint256> unbroadcast_txids;
- file >> unbroadcast_txids;
- unbroadcast = unbroadcast_txids.size();
+ // TODO: remove this try except in v0.22
+ try {
+ std::set<uint256> unbroadcast_txids;
+ file >> unbroadcast_txids;
+ unbroadcast = unbroadcast_txids.size();
- for (const auto& txid : unbroadcast_txids) {
+ for (const auto& txid : unbroadcast_txids) {
pool.AddUnbroadcastTx(txid);
+ }
+ } catch (const std::exception&) {
+ // mempool.dat files created prior to v0.21 will not have an
+ // unbroadcast set. No need to log a failure if parsing fails here.
}
} catch (const std::exception& e) {