aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.bench.include1
-rw-r--r--src/Makefile.test.include35
-rw-r--r--src/bench/hashpadding.cpp47
-rw-r--r--src/blockfilter.h8
-rw-r--r--src/interfaces/chain.cpp4
-rw-r--r--src/interfaces/chain.h3
-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.cpp32
-rw-r--r--src/qt/guiutil.cpp8
-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.cpp4
-rw-r--r--src/rpc/util.cpp8
-rw-r--r--src/script/sigcache.cpp12
-rw-r--r--src/support/lockedpool.cpp1
-rw-r--r--src/support/lockedpool.h4
-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.cpp2
-rw-r--r--src/txmempool.h6
-rw-r--r--src/validation.cpp37
-rw-r--r--src/validationinterface.cpp20
-rw-r--r--src/validationinterface.h9
-rw-r--r--src/wallet/db.cpp3
-rw-r--r--src/wallet/wallet.cpp53
-rw-r--r--src/wallet/wallet.h2
-rw-r--r--src/wallet/walletdb.cpp14
39 files changed, 821 insertions, 199 deletions
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index 766c0fca54..93b5156af3 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -29,6 +29,7 @@ bench_bench_bitcoin_SOURCES = \
bench/crypto_hash.cpp \
bench/ccoins_caching.cpp \
bench/gcs_filter.cpp \
+ bench/hashpadding.cpp \
bench/merkle_root.cpp \
bench/mempool_eviction.cpp \
bench/mempool_stress.cpp \
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/bench/hashpadding.cpp b/src/bench/hashpadding.cpp
new file mode 100644
index 0000000000..985be8bdba
--- /dev/null
+++ b/src/bench/hashpadding.cpp
@@ -0,0 +1,47 @@
+// Copyright (c) 2015-2018 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <bench/bench.h>
+#include <hash.h>
+#include <random.h>
+#include <uint256.h>
+
+
+static void PrePadded(benchmark::State& state)
+{
+
+ CSHA256 hasher;
+
+ // Setup the salted hasher
+ uint256 nonce = GetRandHash();
+ hasher.Write(nonce.begin(), 32);
+ hasher.Write(nonce.begin(), 32);
+ uint256 data = GetRandHash();
+ while (state.KeepRunning()) {
+ unsigned char out[32];
+ CSHA256 h = hasher;
+ h.Write(data.begin(), 32);
+ h.Finalize(out);
+ }
+}
+
+BENCHMARK(PrePadded, 10000);
+
+static void RegularPadded(benchmark::State& state)
+{
+ CSHA256 hasher;
+
+ // Setup the salted hasher
+ uint256 nonce = GetRandHash();
+ uint256 data = GetRandHash();
+ while (state.KeepRunning()) {
+ unsigned char out[32];
+ CSHA256 h = hasher;
+ h.Write(nonce.begin(), 32);
+ h.Write(data.begin(), 32);
+ h.Finalize(out);
+ }
+}
+
+BENCHMARK(RegularPadded, 10000);
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/chain.cpp b/src/interfaces/chain.cpp
index d8e459a8e8..d1e04b114d 100644
--- a/src/interfaces/chain.cpp
+++ b/src/interfaces/chain.cpp
@@ -63,9 +63,9 @@ public:
{
m_notifications->transactionAddedToMempool(tx);
}
- void TransactionRemovedFromMempool(const CTransactionRef& tx) override
+ void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) override
{
- m_notifications->transactionRemovedFromMempool(tx);
+ m_notifications->transactionRemovedFromMempool(tx, reason);
}
void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override
{
diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h
index 7dfc77db7b..61d7ddb934 100644
--- a/src/interfaces/chain.h
+++ b/src/interfaces/chain.h
@@ -20,6 +20,7 @@ class CRPCCommand;
class CScheduler;
class Coin;
class uint256;
+enum class MemPoolRemovalReason;
enum class RBFTransactionState;
struct bilingual_str;
struct CBlockLocator;
@@ -239,7 +240,7 @@ public:
public:
virtual ~Notifications() {}
virtual void transactionAddedToMempool(const CTransactionRef& tx) {}
- virtual void transactionRemovedFromMempool(const CTransactionRef& ptx) {}
+ virtual void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) {}
virtual void blockConnected(const CBlock& block, int height) {}
virtual void blockDisconnected(const CBlock& block, int height) {}
virtual void updatedBlockTip() {}
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 ad74ca3a02..f8cdb5df23 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -65,6 +65,23 @@ Q_DECLARE_METATYPE(CAmount)
Q_DECLARE_METATYPE(SynchronizationState)
Q_DECLARE_METATYPE(uint256)
+static void RegisterMetaTypes()
+{
+ // Register meta types used for QMetaObject::invokeMethod and Qt::QueuedConnection
+ qRegisterMetaType<bool*>();
+ qRegisterMetaType<SynchronizationState>();
+ #ifdef ENABLE_WALLET
+ qRegisterMetaType<WalletModel*>();
+ #endif
+ // Register typedefs (see http://qt-project.org/doc/qt-5/qmetatype.html#qRegisterMetaType)
+ // IMPORTANT: if CAmount is no longer a typedef use the normal variant above (see https://doc.qt.io/qt-5/qmetatype.html#qRegisterMetaType-1)
+ qRegisterMetaType<CAmount>("CAmount");
+ qRegisterMetaType<size_t>("size_t");
+
+ qRegisterMetaType<std::function<void()>>("std::function<void()>");
+ qRegisterMetaType<QMessageBox::Icon>("QMessageBox::Icon");
+}
+
static QString GetLangTerritory()
{
QSettings settings;
@@ -184,6 +201,7 @@ BitcoinApplication::BitcoinApplication(interfaces::Node& node):
returnValue(0),
platformStyle(nullptr)
{
+ RegisterMetaTypes();
setQuitOnLastWindowClosed(false);
}
@@ -433,20 +451,6 @@ int GuiMain(int argc, char* argv[])
BitcoinApplication app(*node);
- // Register meta types used for QMetaObject::invokeMethod and Qt::QueuedConnection
- qRegisterMetaType<bool*>();
- qRegisterMetaType<SynchronizationState>();
-#ifdef ENABLE_WALLET
- qRegisterMetaType<WalletModel*>();
-#endif
- // Register typedefs (see http://qt-project.org/doc/qt-5/qmetatype.html#qRegisterMetaType)
- // IMPORTANT: if CAmount is no longer a typedef use the normal variant above (see https://doc.qt.io/qt-5/qmetatype.html#qRegisterMetaType-1)
- qRegisterMetaType<CAmount>("CAmount");
- qRegisterMetaType<size_t>("size_t");
-
- qRegisterMetaType<std::function<void()>>("std::function<void()>");
- qRegisterMetaType<QMessageBox::Icon>("QMessageBox::Icon");
-
/// 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();
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/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 2a0079ac39..844f62cbc6 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -22,8 +22,6 @@
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 */
@@ -295,6 +293,7 @@ void StartRPC()
void InterruptRPC()
{
+ static std::once_flag g_rpc_interrupt_flag;
// 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");
@@ -305,6 +304,7 @@ void InterruptRPC()
void StopRPC()
{
+ static std::once_flag g_rpc_stop_flag;
// 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, []() {
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/script/sigcache.cpp b/src/script/sigcache.cpp
index e7b6df3ce8..3c54d5bee4 100644
--- a/src/script/sigcache.cpp
+++ b/src/script/sigcache.cpp
@@ -23,7 +23,7 @@ class CSignatureCache
{
private:
//! Entries are SHA256(nonce || signature hash || public key || signature):
- uint256 nonce;
+ CSHA256 m_salted_hasher;
typedef CuckooCache::cache<uint256, SignatureCacheHasher> map_type;
map_type setValid;
boost::shared_mutex cs_sigcache;
@@ -31,13 +31,19 @@ private:
public:
CSignatureCache()
{
- GetRandBytes(nonce.begin(), 32);
+ uint256 nonce = GetRandHash();
+ // We want the nonce to be 64 bytes long to force the hasher to process
+ // this chunk, which makes later hash computations more efficient. We
+ // just write our 32-byte entropy twice to fill the 64 bytes.
+ m_salted_hasher.Write(nonce.begin(), 32);
+ m_salted_hasher.Write(nonce.begin(), 32);
}
void
ComputeEntry(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey)
{
- CSHA256().Write(nonce.begin(), 32).Write(hash.begin(), 32).Write(&pubkey[0], pubkey.size()).Write(&vchSig[0], vchSig.size()).Finalize(entry.begin());
+ CSHA256 hasher = m_salted_hasher;
+ hasher.Write(hash.begin(), 32).Write(&pubkey[0], pubkey.size()).Write(&vchSig[0], vchSig.size()).Finalize(entry.begin());
}
bool
diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp
index f17b539e09..b4f392116c 100644
--- a/src/support/lockedpool.cpp
+++ b/src/support/lockedpool.cpp
@@ -29,7 +29,6 @@
#endif
LockedPoolManager* LockedPoolManager::_instance = nullptr;
-std::once_flag LockedPoolManager::init_flag;
/*******************************************************************************/
// Utilities
diff --git a/src/support/lockedpool.h b/src/support/lockedpool.h
index de668f0773..b9e2e99d1a 100644
--- a/src/support/lockedpool.h
+++ b/src/support/lockedpool.h
@@ -221,7 +221,8 @@ public:
/** Return the current instance, or create it once */
static LockedPoolManager& Instance()
{
- std::call_once(LockedPoolManager::init_flag, LockedPoolManager::CreateInstance);
+ static std::once_flag init_flag;
+ std::call_once(init_flag, LockedPoolManager::CreateInstance);
return *LockedPoolManager::_instance;
}
@@ -234,7 +235,6 @@ private:
static bool LockingFailed();
static LockedPoolManager* _instance;
- static std::once_flag init_flag;
};
#endif // BITCOIN_SUPPORT_LOCKEDPOOL_H
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.cpp b/src/txmempool.cpp
index c5c0208d8f..7d8eb8a323 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -410,7 +410,7 @@ void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason)
// for any reason except being included in a block. Clients interested
// in transactions included in blocks can subscribe to the BlockConnected
// notification.
- GetMainSignals().TransactionRemovedFromMempool(it->GetSharedTx());
+ GetMainSignals().TransactionRemovedFromMempool(it->GetSharedTx(), reason);
}
const uint256 hash = it->GetTx().GetHash();
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..0d57900670 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -1481,14 +1481,21 @@ int GetSpendHeight(const CCoinsViewCache& inputs)
}
-static CuckooCache::cache<uint256, SignatureCacheHasher> scriptExecutionCache;
-static uint256 scriptExecutionCacheNonce(GetRandHash());
+static CuckooCache::cache<uint256, SignatureCacheHasher> g_scriptExecutionCache;
+static CSHA256 g_scriptExecutionCacheHasher;
void InitScriptExecutionCache() {
+ // Setup the salted hasher
+ uint256 nonce = GetRandHash();
+ // We want the nonce to be 64 bytes long to force the hasher to process
+ // this chunk, which makes later hash computations more efficient. We
+ // just write our 32-byte entropy twice to fill the 64 bytes.
+ g_scriptExecutionCacheHasher.Write(nonce.begin(), 32);
+ g_scriptExecutionCacheHasher.Write(nonce.begin(), 32);
// nMaxCacheSize is unsigned. If -maxsigcachesize is set to zero,
// setup_bytes creates the minimum possible cache (2 elements).
size_t nMaxCacheSize = std::min(std::max((int64_t)0, gArgs.GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) / 2), MAX_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20);
- size_t nElems = scriptExecutionCache.setup_bytes(nMaxCacheSize);
+ size_t nElems = g_scriptExecutionCache.setup_bytes(nMaxCacheSize);
LogPrintf("Using %zu MiB out of %zu/2 requested for script execution cache, able to store %zu elements\n",
(nElems*sizeof(uint256)) >>20, (nMaxCacheSize*2)>>20, nElems);
}
@@ -1526,12 +1533,10 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const C
// properly commits to the scriptPubKey in the inputs view of that
// transaction).
uint256 hashCacheEntry;
- // We only use the first 19 bytes of nonce to avoid a second SHA
- // round - giving us 19 + 32 + 4 = 55 bytes (+ 8 + 1 = 64)
- static_assert(55 - sizeof(flags) - 32 >= 128/8, "Want at least 128 bits of nonce for script execution cache");
- CSHA256().Write(scriptExecutionCacheNonce.begin(), 55 - sizeof(flags) - 32).Write(tx.GetWitnessHash().begin(), 32).Write((unsigned char*)&flags, sizeof(flags)).Finalize(hashCacheEntry.begin());
+ CSHA256 hasher = g_scriptExecutionCacheHasher;
+ hasher.Write(tx.GetWitnessHash().begin(), 32).Write((unsigned char*)&flags, sizeof(flags)).Finalize(hashCacheEntry.begin());
AssertLockHeld(cs_main); //TODO: Remove this requirement by making CuckooCache not require external locks
- if (scriptExecutionCache.contains(hashCacheEntry, !cacheFullScriptStore)) {
+ if (g_scriptExecutionCache.contains(hashCacheEntry, !cacheFullScriptStore)) {
return true;
}
@@ -1586,7 +1591,7 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const C
if (cacheFullScriptStore && !pvChecks) {
// We executed all of the provided scripts, and were told to
// cache the result. Do so now.
- scriptExecutionCache.insert(hashCacheEntry);
+ g_scriptExecutionCache.insert(hashCacheEntry);
}
return true;
@@ -5067,12 +5072,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) {
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index 9437f9c817..3dfbcc581c 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -199,22 +199,22 @@ void CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockInd
fInitialDownload);
}
-void CMainSignals::TransactionAddedToMempool(const CTransactionRef &ptx) {
- auto event = [ptx, this] {
- m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionAddedToMempool(ptx); });
+void CMainSignals::TransactionAddedToMempool(const CTransactionRef& tx) {
+ auto event = [tx, this] {
+ m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionAddedToMempool(tx); });
};
ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s", __func__,
- ptx->GetHash().ToString(),
- ptx->GetWitnessHash().ToString());
+ tx->GetHash().ToString(),
+ tx->GetWitnessHash().ToString());
}
-void CMainSignals::TransactionRemovedFromMempool(const CTransactionRef &ptx) {
- auto event = [ptx, this] {
- m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionRemovedFromMempool(ptx); });
+void CMainSignals::TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) {
+ auto event = [tx, reason, this] {
+ m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionRemovedFromMempool(tx, reason); });
};
ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s", __func__,
- ptx->GetHash().ToString(),
- ptx->GetWitnessHash().ToString());
+ tx->GetHash().ToString(),
+ tx->GetWitnessHash().ToString());
}
void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex) {
diff --git a/src/validationinterface.h b/src/validationinterface.h
index 9c23965bc1..e96f2883fc 100644
--- a/src/validationinterface.h
+++ b/src/validationinterface.h
@@ -21,6 +21,7 @@ class CConnman;
class CValidationInterface;
class uint256;
class CScheduler;
+enum class MemPoolRemovalReason;
/** Register subscriber */
void RegisterValidationInterface(CValidationInterface* callbacks);
@@ -96,7 +97,7 @@ protected:
*
* Called on a background thread.
*/
- virtual void TransactionAddedToMempool(const CTransactionRef &ptxn) {}
+ virtual void TransactionAddedToMempool(const CTransactionRef& tx) {}
/**
* Notifies listeners of a transaction leaving mempool.
*
@@ -129,7 +130,7 @@ protected:
*
* Called on a background thread.
*/
- virtual void TransactionRemovedFromMempool(const CTransactionRef &ptx) {}
+ virtual void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) {}
/**
* Notifies listeners of a block being connected.
* Provides a vector of transactions evicted from the mempool as a result.
@@ -196,8 +197,8 @@ public:
void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload);
- void TransactionAddedToMempool(const CTransactionRef &);
- void TransactionRemovedFromMempool(const CTransactionRef &);
+ void TransactionAddedToMempool(const CTransactionRef&);
+ void TransactionRemovedFromMempool(const CTransactionRef&, MemPoolRemovalReason);
void BlockConnected(const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex);
void BlockDisconnected(const std::shared_ptr<const CBlock> &, const CBlockIndex* pindex);
void ChainStateFlushed(const CBlockLocator &);
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index 4ed28b0623..d90e8e6433 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -14,8 +14,6 @@
#include <sys/stat.h>
#endif
-#include <boost/thread.hpp>
-
namespace {
//! Make sure database has a unique fileid within the environment. If it
@@ -671,7 +669,6 @@ bool BerkeleyBatch::PeriodicFlush(BerkeleyDatabase& database)
if (nRefCount == 0)
{
- boost::this_thread::interruption_point();
std::map<std::string, int>::iterator mi = env->mapFileUseCount.find(strFile);
if (mi != env->mapFileUseCount.end())
{
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 7824563254..89737ca7b5 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -21,6 +21,7 @@
#include <script/descriptor.h>
#include <script/script.h>
#include <script/signingprovider.h>
+#include <txmempool.h>
#include <util/bip32.h>
#include <util/check.h>
#include <util/error.h>
@@ -1100,23 +1101,52 @@ void CWallet::SyncTransaction(const CTransactionRef& ptx, CWalletTx::Confirmatio
MarkInputsDirty(ptx);
}
-void CWallet::transactionAddedToMempool(const CTransactionRef& ptx) {
+void CWallet::transactionAddedToMempool(const CTransactionRef& tx) {
LOCK(cs_wallet);
- CWalletTx::Confirmation confirm(CWalletTx::Status::UNCONFIRMED, /* block_height */ 0, {}, /* nIndex */ 0);
- SyncTransaction(ptx, confirm);
+ SyncTransaction(tx, {CWalletTx::Status::UNCONFIRMED, /* block height */ 0, /* block hash */ {}, /* index */ 0});
- auto it = mapWallet.find(ptx->GetHash());
+ auto it = mapWallet.find(tx->GetHash());
if (it != mapWallet.end()) {
it->second.fInMempool = true;
}
}
-void CWallet::transactionRemovedFromMempool(const CTransactionRef &ptx) {
+void CWallet::transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) {
LOCK(cs_wallet);
- auto it = mapWallet.find(ptx->GetHash());
+ auto it = mapWallet.find(tx->GetHash());
if (it != mapWallet.end()) {
it->second.fInMempool = false;
}
+ // Handle transactions that were removed from the mempool because they
+ // conflict with transactions in a newly connected block.
+ if (reason == MemPoolRemovalReason::CONFLICT) {
+ // Call SyncNotifications, so external -walletnotify notifications will
+ // be triggered for these transactions. Set Status::UNCONFIRMED instead
+ // of Status::CONFLICTED for a few reasons:
+ //
+ // 1. The transactionRemovedFromMempool callback does not currently
+ // provide the conflicting block's hash and height, and for backwards
+ // compatibility reasons it may not be not safe to store conflicted
+ // wallet transactions with a null block hash. See
+ // https://github.com/bitcoin/bitcoin/pull/18600#discussion_r420195993.
+ // 2. For most of these transactions, the wallet's internal conflict
+ // detection in the blockConnected handler will subsequently call
+ // MarkConflicted and update them with CONFLICTED status anyway. This
+ // applies to any wallet transaction that has inputs spent in the
+ // block, or that has ancestors in the wallet with inputs spent by
+ // the block.
+ // 3. Longstanding behavior since the sync implementation in
+ // https://github.com/bitcoin/bitcoin/pull/9371 and the prior sync
+ // implementation before that was to mark these transactions
+ // unconfirmed rather than conflicted.
+ //
+ // Nothing described above should be seen as an unchangeable requirement
+ // when improving this code in the future. The wallet's heuristics for
+ // distinguishing between conflicted and unconfirmed transactions are
+ // imperfect, and could be improved in general, see
+ // https://github.com/bitcoin-core/bitcoin-devwiki/wiki/Wallet-Transaction-Conflict-Tracking
+ SyncTransaction(tx, {CWalletTx::Status::UNCONFIRMED, /* block height */ 0, /* block hash */ {}, /* index */ 0});
+ }
}
void CWallet::blockConnected(const CBlock& block, int height)
@@ -1127,9 +1157,8 @@ void CWallet::blockConnected(const CBlock& block, int height)
m_last_block_processed_height = height;
m_last_block_processed = block_hash;
for (size_t index = 0; index < block.vtx.size(); index++) {
- CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, height, block_hash, index);
- SyncTransaction(block.vtx[index], confirm);
- transactionRemovedFromMempool(block.vtx[index]);
+ SyncTransaction(block.vtx[index], {CWalletTx::Status::CONFIRMED, height, block_hash, (int)index});
+ transactionRemovedFromMempool(block.vtx[index], MemPoolRemovalReason::BLOCK);
}
}
@@ -1144,8 +1173,7 @@ void CWallet::blockDisconnected(const CBlock& block, int height)
m_last_block_processed_height = height - 1;
m_last_block_processed = block.hashPrevBlock;
for (const CTransactionRef& ptx : block.vtx) {
- CWalletTx::Confirmation confirm(CWalletTx::Status::UNCONFIRMED, /* block_height */ 0, {}, /* nIndex */ 0);
- SyncTransaction(ptx, confirm);
+ SyncTransaction(ptx, {CWalletTx::Status::UNCONFIRMED, /* block height */ 0, /* block hash */ {}, /* index */ 0});
}
}
@@ -1685,8 +1713,7 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
break;
}
for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) {
- CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, block_height, block_hash, posInBlock);
- SyncTransaction(block.vtx[posInBlock], confirm, fUpdate);
+ SyncTransaction(block.vtx[posInBlock], {CWalletTx::Status::CONFIRMED, block_height, block_hash, (int)posInBlock}, fUpdate);
}
// scan succeeded, record block as most recent successfully scanned
result.last_scanned_block = block_hash;
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index e3141baef0..67331dc3be 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -921,7 +921,7 @@ public:
uint256 last_failed_block;
};
ScanResult ScanForWalletTransactions(const uint256& start_block, int start_height, Optional<int> max_height, const WalletRescanReserver& reserver, bool fUpdate);
- void transactionRemovedFromMempool(const CTransactionRef &ptx) override;
+ void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) override;
void ReacceptWalletTransactions() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void ResendWalletTransactions();
struct Balance {
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index e7adbfea77..cb516f70f0 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -18,8 +18,6 @@
#include <atomic>
#include <string>
-#include <boost/thread.hpp>
-
namespace DBKeys {
const std::string ACENTRY{"acentry"};
const std::string ACTIVEEXTERNALSPK{"activeexternalspk"};
@@ -745,11 +743,7 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
pwallet->WalletLogPrintf("%s\n", strErr);
}
pcursor->close();
- }
- catch (const boost::thread_interrupted&) {
- throw;
- }
- catch (...) {
+ } catch (...) {
result = DBErrors::CORRUPT;
}
@@ -887,11 +881,7 @@ DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWal
}
}
pcursor->close();
- }
- catch (const boost::thread_interrupted&) {
- throw;
- }
- catch (...) {
+ } catch (...) {
result = DBErrors::CORRUPT;
}