aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--depends/packages/qt.mk9
-rw-r--r--doc/developer-notes.md2
-rw-r--r--doc/release-notes.md3
-rw-r--r--src/Makefile.test.include7
-rw-r--r--src/interfaces/chain.cpp2
-rw-r--r--src/interfaces/node.cpp4
-rw-r--r--src/node/coin.cpp8
-rw-r--r--src/node/coin.h4
-rw-r--r--src/node/transaction.cpp5
-rw-r--r--src/qt/test/wallettests.cpp1
-rw-r--r--src/rest.cpp39
-rw-r--r--src/rpc/blockchain.cpp20
-rw-r--r--src/rpc/mining.cpp6
-rw-r--r--src/rpc/rawtransaction.cpp5
-rw-r--r--src/test/base32_tests.cpp11
-rw-r--r--src/test/base64_tests.cpp11
-rw-r--r--src/test/fuzz/block.cpp63
-rw-r--r--src/test/rpc_tests.cpp4
-rw-r--r--src/test/util_tests.cpp5
-rw-r--r--src/util/moneystr.cpp4
-rw-r--r--src/util/strencodings.cpp12
-rwxr-xr-xtest/fuzz/test_runner.py1
22 files changed, 194 insertions, 32 deletions
diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk
index 2087fec14d..efa76965d5 100644
--- a/depends/packages/qt.mk
+++ b/depends/packages/qt.mk
@@ -39,12 +39,14 @@ $(package)_config_opts += -no-iconv
$(package)_config_opts += -no-kms
$(package)_config_opts += -no-linuxfb
$(package)_config_opts += -no-libjpeg
+$(package)_config_opts += -no-libproxy
$(package)_config_opts += -no-libudev
$(package)_config_opts += -no-mtdev
$(package)_config_opts += -no-openssl
$(package)_config_opts += -no-openvg
$(package)_config_opts += -no-reduce-relocations
$(package)_config_opts += -no-qml-debug
+$(package)_config_opts += -no-sctp
$(package)_config_opts += -no-securetransport
$(package)_config_opts += -no-sql-db2
$(package)_config_opts += -no-sql-ibase
@@ -55,12 +57,13 @@ $(package)_config_opts += -no-sql-odbc
$(package)_config_opts += -no-sql-psql
$(package)_config_opts += -no-sql-sqlite
$(package)_config_opts += -no-sql-sqlite2
+$(package)_config_opts += -no-system-proxies
$(package)_config_opts += -no-use-gold-linker
$(package)_config_opts += -no-xinput2
$(package)_config_opts += -nomake examples
$(package)_config_opts += -nomake tests
$(package)_config_opts += -opensource
-$(package)_config_opts += -optimized-qmake
+$(package)_config_opts += -optimized-tools
$(package)_config_opts += -pch
$(package)_config_opts += -pkg-config
$(package)_config_opts += -prefix $(host_prefix)
@@ -79,9 +82,12 @@ $(package)_config_opts += -no-feature-dial
$(package)_config_opts += -no-feature-filesystemwatcher
$(package)_config_opts += -no-feature-fontcombobox
$(package)_config_opts += -no-feature-ftp
+$(package)_config_opts += -no-feature-http
$(package)_config_opts += -no-feature-image_heuristic_mask
$(package)_config_opts += -no-feature-keysequenceedit
$(package)_config_opts += -no-feature-lcdnumber
+$(package)_config_opts += -no-feature-networkdiskcache
+$(package)_config_opts += -no-feature-networkproxy
$(package)_config_opts += -no-feature-pdf
$(package)_config_opts += -no-feature-printdialog
$(package)_config_opts += -no-feature-printer
@@ -89,6 +95,7 @@ $(package)_config_opts += -no-feature-printpreviewdialog
$(package)_config_opts += -no-feature-printpreviewwidget
$(package)_config_opts += -no-feature-regularexpression
$(package)_config_opts += -no-feature-sessionmanager
+$(package)_config_opts += -no-feature-socks5
$(package)_config_opts += -no-feature-sql
$(package)_config_opts += -no-feature-statemachine
$(package)_config_opts += -no-feature-syntaxhighlighter
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index 31d9f4e6d4..b50f552e92 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -820,7 +820,7 @@ Current subtrees include:
- **Note**: Follow the instructions in [Upgrading LevelDB](#upgrading-leveldb) when
merging upstream changes to the LevelDB subtree.
-- src/libsecp256k1
+- src/secp256k1
- Upstream at https://github.com/bitcoin-core/secp256k1/ ; actively maintained by Core contributors.
- src/crypto/ctaes
diff --git a/doc/release-notes.md b/doc/release-notes.md
index cdf83178c6..eec1ef9c46 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -78,6 +78,9 @@ New RPCs
New settings
------------
+- RPC Whitelist system. It can give certain RPC users permissions to only some RPC calls.
+It can be set with two command line arguments (`rpcwhitelist` and `rpcwhitelistdefault`). (#12763)
+
Updated settings
----------------
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 0225edf29e..a8845b4c7d 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -9,6 +9,7 @@ FUZZ_TARGETS = \
test/fuzz/addrman_deserialize \
test/fuzz/banentry_deserialize \
test/fuzz/bech32 \
+ test/fuzz/block \
test/fuzz/block_deserialize \
test/fuzz/block_file_info_deserialize \
test/fuzz/block_filter_deserialize \
@@ -229,6 +230,12 @@ test_test_bitcoin_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
if ENABLE_FUZZ
+test_fuzz_block_SOURCES = $(FUZZ_SUITE) test/fuzz/block.cpp
+test_fuzz_block_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+test_fuzz_block_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_block_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_block_LDADD = $(FUZZ_SUITE_LD_COMMON)
+
test_fuzz_block_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp
test_fuzz_block_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCK_DESERIALIZE=1
test_fuzz_block_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp
index 26856a00d3..ac640aa35a 100644
--- a/src/interfaces/chain.cpp
+++ b/src/interfaces/chain.cpp
@@ -263,7 +263,7 @@ public:
}
return true;
}
- void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(coins); }
+ void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(m_node, coins); }
double guessVerificationProgress(const uint256& block_hash) override
{
LOCK(cs_main);
diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp
index c9b820a6ce..529fa793dd 100644
--- a/src/interfaces/node.cpp
+++ b/src/interfaces/node.cpp
@@ -167,8 +167,8 @@ public:
}
int64_t getTotalBytesRecv() override { return m_context.connman ? m_context.connman->GetTotalBytesRecv() : 0; }
int64_t getTotalBytesSent() override { return m_context.connman ? m_context.connman->GetTotalBytesSent() : 0; }
- size_t getMempoolSize() override { return ::mempool.size(); }
- size_t getMempoolDynamicUsage() override { return ::mempool.DynamicMemoryUsage(); }
+ size_t getMempoolSize() override { return m_context.mempool ? m_context.mempool->size() : 0; }
+ size_t getMempoolDynamicUsage() override { return m_context.mempool ? m_context.mempool->DynamicMemoryUsage() : 0; }
bool getHeaderTip(int& height, int64_t& block_time) override
{
LOCK(::cs_main);
diff --git a/src/node/coin.cpp b/src/node/coin.cpp
index ad8d1d3af4..f4f86cdbe9 100644
--- a/src/node/coin.cpp
+++ b/src/node/coin.cpp
@@ -4,14 +4,16 @@
#include <node/coin.h>
+#include <node/context.h>
#include <txmempool.h>
#include <validation.h>
-void FindCoins(std::map<COutPoint, Coin>& coins)
+void FindCoins(const NodeContext& node, std::map<COutPoint, Coin>& coins)
{
- LOCK2(cs_main, ::mempool.cs);
+ assert(node.mempool);
+ LOCK2(cs_main, node.mempool->cs);
CCoinsViewCache& chain_view = ::ChainstateActive().CoinsTip();
- CCoinsViewMemPool mempool_view(&chain_view, ::mempool);
+ CCoinsViewMemPool mempool_view(&chain_view, *node.mempool);
for (auto& coin : coins) {
if (!mempool_view.GetCoin(coin.first, coin.second)) {
// Either the coin is not in the CCoinsViewCache or is spent. Clear it.
diff --git a/src/node/coin.h b/src/node/coin.h
index eb95b75cfb..908850e2a5 100644
--- a/src/node/coin.h
+++ b/src/node/coin.h
@@ -9,14 +9,16 @@
class COutPoint;
class Coin;
+struct NodeContext;
/**
* Look up unspent output information. Returns coins in the mempool and in the
* current chain UTXO set. Iterates through all the keys in the map and
* populates the values.
*
+ * @param[in] node The node context to use for lookup
* @param[in,out] coins map to fill
*/
-void FindCoins(std::map<COutPoint, Coin>& coins);
+void FindCoins(const NodeContext& node, std::map<COutPoint, Coin>& coins);
#endif // BITCOIN_NODE_COIN_H
diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp
index 3c0df2b26e..5e2e502015 100644
--- a/src/node/transaction.cpp
+++ b/src/node/transaction.cpp
@@ -20,6 +20,7 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
// node.connman is assigned both before chain clients and before RPC server is accepting calls,
// and reset after chain clients and RPC sever are stopped. node.connman should never be null here.
assert(node.connman);
+ assert(node.mempool);
std::promise<void> promise;
uint256 hashTx = tx->GetHash();
bool callback_set = false;
@@ -35,10 +36,10 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
// So if the output does exist, then this transaction exists in the chain.
if (!existingCoin.IsSpent()) return TransactionError::ALREADY_IN_CHAIN;
}
- if (!mempool.exists(hashTx)) {
+ if (!node.mempool->exists(hashTx)) {
// Transaction is not already in the mempool. Submit it.
TxValidationState state;
- if (!AcceptToMemoryPool(mempool, state, std::move(tx),
+ if (!AcceptToMemoryPool(*node.mempool, state, std::move(tx),
nullptr /* plTxnReplaced */, false /* bypass_limits */, max_tx_fee)) {
err_string = FormatStateMessage(state);
if (state.IsInvalid()) {
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index dfd56511ea..f6d2816ff8 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -134,6 +134,7 @@ void TestGUI(interfaces::Node& node)
test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey()));
}
node.context()->connman = std::move(test.m_node.connman);
+ node.context()->mempool = std::move(test.m_node.mempool);
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), WalletLocation(), WalletDatabase::CreateMock());
bool firstRun;
wallet->LoadWallet(firstRun);
diff --git a/src/rest.cpp b/src/rest.cpp
index 228c122de3..55756ecfdf 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -8,6 +8,7 @@
#include <core_io.h>
#include <httpserver.h>
#include <index/txindex.h>
+#include <node/context.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
#include <rpc/blockchain.h>
@@ -16,6 +17,7 @@
#include <streams.h>
#include <sync.h>
#include <txmempool.h>
+#include <util/check.h>
#include <util/strencodings.h>
#include <validation.h>
#include <version.h>
@@ -69,6 +71,24 @@ static bool RESTERR(HTTPRequest* req, enum HTTPStatusCode status, std::string me
return false;
}
+/**
+ * Get the node context mempool.
+ *
+ * Set the HTTP error and return nullptr if node context
+ * mempool is not found.
+ *
+ * @param[in] req the HTTP request
+ * return pointer to the mempool or nullptr if no mempool found
+ */
+static CTxMemPool* GetMemPool(HTTPRequest* req)
+{
+ if (!g_rpc_node || !g_rpc_node->mempool) {
+ RESTERR(req, HTTP_NOT_FOUND, "Mempool disabled or instance not found");
+ return nullptr;
+ }
+ return g_rpc_node->mempool;
+}
+
static RetFormat ParseDataFormat(std::string& param, const std::string& strReq)
{
const std::string::size_type pos = strReq.rfind('.');
@@ -295,12 +315,14 @@ static bool rest_mempool_info(HTTPRequest* req, const std::string& strURIPart)
{
if (!CheckWarmup(req))
return false;
+ const CTxMemPool* mempool = GetMemPool(req);
+ if (!mempool) return false;
std::string param;
const RetFormat rf = ParseDataFormat(param, strURIPart);
switch (rf) {
case RetFormat::JSON: {
- UniValue mempoolInfoObject = MempoolInfoToJSON(::mempool);
+ UniValue mempoolInfoObject = MempoolInfoToJSON(*mempool);
std::string strJSON = mempoolInfoObject.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
@@ -315,14 +337,15 @@ static bool rest_mempool_info(HTTPRequest* req, const std::string& strURIPart)
static bool rest_mempool_contents(HTTPRequest* req, const std::string& strURIPart)
{
- if (!CheckWarmup(req))
- return false;
+ if (!CheckWarmup(req)) return false;
+ const CTxMemPool* mempool = GetMemPool(req);
+ if (!mempool) return false;
std::string param;
const RetFormat rf = ParseDataFormat(param, strURIPart);
switch (rf) {
case RetFormat::JSON: {
- UniValue mempoolObject = MempoolToJSON(::mempool, true);
+ UniValue mempoolObject = MempoolToJSON(*mempool, true);
std::string strJSON = mempoolObject.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
@@ -500,11 +523,13 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
};
if (fCheckMemPool) {
+ const CTxMemPool* mempool = GetMemPool(req);
+ if (!mempool) return false;
// use db+mempool as cache backend in case user likes to query mempool
- LOCK2(cs_main, mempool.cs);
+ LOCK2(cs_main, mempool->cs);
CCoinsViewCache& viewChain = ::ChainstateActive().CoinsTip();
- CCoinsViewMemPool viewMempool(&viewChain, mempool);
- process_utxos(viewMempool, mempool);
+ CCoinsViewMemPool viewMempool(&viewChain, *mempool);
+ process_utxos(viewMempool, *mempool);
} else {
LOCK(cs_main); // no need to lock mempool!
process_utxos(::ChainstateActive().CoinsTip(), CTxMemPool());
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 1a65cff332..eb5148eebd 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -528,7 +528,7 @@ static UniValue getrawmempool(const JSONRPCRequest& request)
if (!request.params[0].isNull())
fVerbose = request.params[0].get_bool();
- return MempoolToJSON(::mempool, fVerbose);
+ return MempoolToJSON(EnsureMemPool(), fVerbose);
}
static UniValue getmempoolancestors(const JSONRPCRequest& request)
@@ -566,6 +566,7 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request)
uint256 hash = ParseHashV(request.params[0], "parameter 1");
+ const CTxMemPool& mempool = EnsureMemPool();
LOCK(mempool.cs);
CTxMemPool::txiter it = mempool.mapTx.find(hash);
@@ -591,7 +592,7 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request)
const CTxMemPoolEntry &e = *ancestorIt;
const uint256& _hash = e.GetTx().GetHash();
UniValue info(UniValue::VOBJ);
- entryToJSON(::mempool, info, e);
+ entryToJSON(mempool, info, e);
o.pushKV(_hash.ToString(), info);
}
return o;
@@ -633,6 +634,7 @@ static UniValue getmempooldescendants(const JSONRPCRequest& request)
uint256 hash = ParseHashV(request.params[0], "parameter 1");
+ const CTxMemPool& mempool = EnsureMemPool();
LOCK(mempool.cs);
CTxMemPool::txiter it = mempool.mapTx.find(hash);
@@ -658,7 +660,7 @@ static UniValue getmempooldescendants(const JSONRPCRequest& request)
const CTxMemPoolEntry &e = *descendantIt;
const uint256& _hash = e.GetTx().GetHash();
UniValue info(UniValue::VOBJ);
- entryToJSON(::mempool, info, e);
+ entryToJSON(mempool, info, e);
o.pushKV(_hash.ToString(), info);
}
return o;
@@ -685,6 +687,7 @@ static UniValue getmempoolentry(const JSONRPCRequest& request)
uint256 hash = ParseHashV(request.params[0], "parameter 1");
+ const CTxMemPool& mempool = EnsureMemPool();
LOCK(mempool.cs);
CTxMemPool::txiter it = mempool.mapTx.find(hash);
@@ -694,7 +697,7 @@ static UniValue getmempoolentry(const JSONRPCRequest& request)
const CTxMemPoolEntry &e = *it;
UniValue info(UniValue::VOBJ);
- entryToJSON(::mempool, info, e);
+ entryToJSON(mempool, info, e);
return info;
}
@@ -1070,6 +1073,7 @@ UniValue gettxout(const JSONRPCRequest& request)
CCoinsViewCache* coins_view = &::ChainstateActive().CoinsTip();
if (fMempool) {
+ const CTxMemPool& mempool = EnsureMemPool();
LOCK(mempool.cs);
CCoinsViewMemPool view(coins_view, mempool);
if (!view.GetCoin(out, coin) || mempool.isSpent(out)) {
@@ -1448,7 +1452,7 @@ static UniValue getmempoolinfo(const JSONRPCRequest& request)
},
}.Check(request);
- return MempoolInfoToJSON(::mempool);
+ return MempoolInfoToJSON(EnsureMemPool());
}
static UniValue preciousblock(const JSONRPCRequest& request)
@@ -1964,11 +1968,13 @@ static UniValue savemempool(const JSONRPCRequest& request)
},
}.Check(request);
- if (!::mempool.IsLoaded()) {
+ const CTxMemPool& mempool = EnsureMemPool();
+
+ if (!mempool.IsLoaded()) {
throw JSONRPCError(RPC_MISC_ERROR, "The mempool was not loaded yet");
}
- if (!DumpMempool(::mempool)) {
+ if (!DumpMempool(mempool)) {
throw JSONRPCError(RPC_MISC_ERROR, "Unable to dump mempool to disk");
}
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index d616445b31..9f7f7837d3 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -244,6 +244,7 @@ static UniValue getmininginfo(const JSONRPCRequest& request)
}.Check(request);
LOCK(cs_main);
+ const CTxMemPool& mempool = EnsureMemPool();
UniValue obj(UniValue::VOBJ);
obj.pushKV("blocks", (int)::ChainActive().Height());
@@ -290,7 +291,7 @@ static UniValue prioritisetransaction(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Priority is no longer supported, dummy argument to prioritisetransaction must be 0.");
}
- mempool.PrioritiseTransaction(hash, nAmount);
+ EnsureMemPool().PrioritiseTransaction(hash, nAmount);
return true;
}
@@ -476,6 +477,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME " is in initial sync and waiting for blocks...");
static unsigned int nTransactionsUpdatedLast;
+ const CTxMemPool& mempool = EnsureMemPool();
if (!lpval.isNull())
{
@@ -510,7 +512,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
if (g_best_block_cv.wait_until(lock, checktxtime) == std::cv_status::timeout)
{
// Timeout: Check transactions for update
- // without holding ::mempool.cs to avoid deadlocks
+ // without holding the mempool lock to avoid deadlocks
if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP)
break;
checktxtime += std::chrono::seconds(10);
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index b816a54d2f..5be7acce1c 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -636,6 +636,7 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request)
CCoinsView viewDummy;
CCoinsViewCache view(&viewDummy);
{
+ const CTxMemPool& mempool = EnsureMemPool();
LOCK(cs_main);
LOCK(mempool.cs);
CCoinsViewCache &viewChain = ::ChainstateActive().CoinsTip();
@@ -758,7 +759,7 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
for (const CTxIn& txin : mtx.vin) {
coins[txin.prevout]; // Create empty map entry keyed by prevout.
}
- FindCoins(coins);
+ FindCoins(*g_rpc_node, coins);
// Parse the prevtxs array
ParsePrevouts(request.params[2], &keystore, coins);
@@ -890,6 +891,7 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
max_raw_tx_fee_rate = CFeeRate(AmountFromValue(request.params[1]));
}
+ CTxMemPool& mempool = EnsureMemPool();
int64_t virtual_size = GetVirtualTransactionSize(*tx);
CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
@@ -1508,6 +1510,7 @@ UniValue utxoupdatepsbt(const JSONRPCRequest& request)
CCoinsView viewDummy;
CCoinsViewCache view(&viewDummy);
{
+ const CTxMemPool& mempool = EnsureMemPool();
LOCK2(cs_main, mempool.cs);
CCoinsViewCache &viewChain = ::ChainstateActive().CoinsTip();
CCoinsViewMemPool viewMempool(&viewChain, mempool);
diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp
index bd6ece935b..690368b177 100644
--- a/src/test/base32_tests.cpp
+++ b/src/test/base32_tests.cpp
@@ -20,6 +20,17 @@ BOOST_AUTO_TEST_CASE(base32_testvectors)
std::string strDec = DecodeBase32(vstrOut[i]);
BOOST_CHECK_EQUAL(strDec, vstrIn[i]);
}
+
+ // Decoding strings with embedded NUL characters should fail
+ bool failure;
+ (void)DecodeBase32(std::string("invalid", 7), &failure);
+ BOOST_CHECK_EQUAL(failure, true);
+ (void)DecodeBase32(std::string("AWSX3VPP", 8), &failure);
+ BOOST_CHECK_EQUAL(failure, false);
+ (void)DecodeBase32(std::string("AWSX3VPP\0invalid", 16), &failure);
+ BOOST_CHECK_EQUAL(failure, true);
+ (void)DecodeBase32(std::string("AWSX3VPPinvalid", 15), &failure);
+ BOOST_CHECK_EQUAL(failure, true);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp
index a5fed55504..94df4d1955 100644
--- a/src/test/base64_tests.cpp
+++ b/src/test/base64_tests.cpp
@@ -20,6 +20,17 @@ BOOST_AUTO_TEST_CASE(base64_testvectors)
std::string strDec = DecodeBase64(strEnc);
BOOST_CHECK_EQUAL(strDec, vstrIn[i]);
}
+
+ // Decoding strings with embedded NUL characters should fail
+ bool failure;
+ (void)DecodeBase64(std::string("invalid", 7), &failure);
+ BOOST_CHECK_EQUAL(failure, true);
+ (void)DecodeBase64(std::string("nQB/pZw=", 8), &failure);
+ BOOST_CHECK_EQUAL(failure, false);
+ (void)DecodeBase64(std::string("nQB/pZw=\0invalid", 16), &failure);
+ BOOST_CHECK_EQUAL(failure, true);
+ (void)DecodeBase64(std::string("nQB/pZw=invalid", 15), &failure);
+ BOOST_CHECK_EQUAL(failure, true);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/fuzz/block.cpp b/src/test/fuzz/block.cpp
new file mode 100644
index 0000000000..431248de4a
--- /dev/null
+++ b/src/test/fuzz/block.cpp
@@ -0,0 +1,63 @@
+// Copyright (c) 2019 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 <consensus/merkle.h>
+#include <consensus/validation.h>
+#include <core_io.h>
+#include <core_memusage.h>
+#include <pubkey.h>
+#include <primitives/block.h>
+#include <streams.h>
+#include <test/fuzz/fuzz.h>
+#include <validation.h>
+#include <version.h>
+
+#include <cassert>
+#include <string>
+
+void initialize()
+{
+ const static auto verify_handle = MakeUnique<ECCVerifyHandle>();
+ SelectParams(CBaseChainParams::REGTEST);
+}
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION);
+ CBlock block;
+ try {
+ int nVersion;
+ ds >> nVersion;
+ ds.SetVersion(nVersion);
+ ds >> block;
+ } catch (const std::ios_base::failure&) {
+ return;
+ }
+ const Consensus::Params& consensus_params = Params().GetConsensus();
+ BlockValidationState validation_state_pow_and_merkle;
+ const bool valid_incl_pow_and_merkle = CheckBlock(block, validation_state_pow_and_merkle, consensus_params, /* fCheckPOW= */ true, /* fCheckMerkleRoot= */ true);
+ BlockValidationState validation_state_pow;
+ const bool valid_incl_pow = CheckBlock(block, validation_state_pow, consensus_params, /* fCheckPOW= */ true, /* fCheckMerkleRoot= */ false);
+ BlockValidationState validation_state_merkle;
+ const bool valid_incl_merkle = CheckBlock(block, validation_state_merkle, consensus_params, /* fCheckPOW= */ false, /* fCheckMerkleRoot= */ true);
+ BlockValidationState validation_state_none;
+ const bool valid_incl_none = CheckBlock(block, validation_state_none, consensus_params, /* fCheckPOW= */ false, /* fCheckMerkleRoot= */ false);
+ if (valid_incl_pow_and_merkle) {
+ assert(valid_incl_pow && valid_incl_merkle && valid_incl_none);
+ } else if (valid_incl_merkle || valid_incl_pow) {
+ assert(valid_incl_none);
+ }
+ (void)block.GetHash();
+ (void)block.ToString();
+ (void)BlockMerkleRoot(block);
+ if (!block.vtx.empty()) {
+ // TODO: Avoid array index out of bounds error in BlockWitnessMerkleRoot
+ // when block.vtx.empty().
+ (void)BlockWitnessMerkleRoot(block);
+ }
+ (void)GetBlockWeight(block);
+ (void)GetWitnessCommitmentIndex(block);
+ (void)RecursiveDynamicUsage(block);
+}
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 52dd22de7e..84a3980b19 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -112,14 +112,10 @@ BOOST_AUTO_TEST_CASE(rpc_rawsign)
std::string notsigned = r.get_str();
std::string privkey1 = "\"KzsXybp9jX64P5ekX1KUxRQ79Jht9uzW7LorgwE65i5rWACL6LQe\"";
std::string privkey2 = "\"Kyhdf5LuKTRx4ge69ybABsiUAWjVRK4XGxAKk2FQLp2HjGMy87Z4\"";
- NodeContext node;
- node.chain = interfaces::MakeChain(node);
- g_rpc_node = &node;
r = CallRPC(std::string("signrawtransactionwithkey ")+notsigned+" [] "+prevout);
BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == false);
r = CallRPC(std::string("signrawtransactionwithkey ")+notsigned+" ["+privkey1+","+privkey2+"] "+prevout);
BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == true);
- g_rpc_node = nullptr;
}
BOOST_AUTO_TEST_CASE(rpc_createraw_op_return)
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index b9fcd97a8f..a5cbae89b4 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -1069,6 +1069,11 @@ BOOST_AUTO_TEST_CASE(util_ParseMoney)
// Parsing negative amounts must fail
BOOST_CHECK(!ParseMoney("-1", ret));
+
+ // Parsing strings with embedded NUL characters should fail
+ BOOST_CHECK(!ParseMoney(std::string("\0-1", 3), ret));
+ BOOST_CHECK(!ParseMoney(std::string("\01", 2), ret));
+ BOOST_CHECK(!ParseMoney(std::string("1\0", 2), ret));
}
BOOST_AUTO_TEST_CASE(util_IsHex)
diff --git a/src/util/moneystr.cpp b/src/util/moneystr.cpp
index ba5a12e58c..3e75a2e3e9 100644
--- a/src/util/moneystr.cpp
+++ b/src/util/moneystr.cpp
@@ -7,6 +7,7 @@
#include <tinyformat.h>
#include <util/strencodings.h>
+#include <util/string.h>
std::string FormatMoney(const CAmount& n)
{
@@ -32,6 +33,9 @@ std::string FormatMoney(const CAmount& n)
bool ParseMoney(const std::string& str, CAmount& nRet)
{
+ if (!ValidAsCString(str)) {
+ return false;
+ }
return ParseMoney(str.c_str(), nRet);
}
diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp
index 8f2d05f03b..31719cd975 100644
--- a/src/util/strencodings.cpp
+++ b/src/util/strencodings.cpp
@@ -191,6 +191,12 @@ std::vector<unsigned char> DecodeBase64(const char* p, bool* pf_invalid)
std::string DecodeBase64(const std::string& str, bool* pf_invalid)
{
+ if (!ValidAsCString(str)) {
+ if (pf_invalid) {
+ *pf_invalid = true;
+ }
+ return {};
+ }
std::vector<unsigned char> vchRet = DecodeBase64(str.c_str(), pf_invalid);
return std::string((const char*)vchRet.data(), vchRet.size());
}
@@ -260,6 +266,12 @@ std::vector<unsigned char> DecodeBase32(const char* p, bool* pf_invalid)
std::string DecodeBase32(const std::string& str, bool* pf_invalid)
{
+ if (!ValidAsCString(str)) {
+ if (pf_invalid) {
+ *pf_invalid = true;
+ }
+ return {};
+ }
std::vector<unsigned char> vchRet = DecodeBase32(str.c_str(), pf_invalid);
return std::string((const char*)vchRet.data(), vchRet.size());
}
diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py
index 2d255c0bb4..8b503d83bf 100755
--- a/test/fuzz/test_runner.py
+++ b/test/fuzz/test_runner.py
@@ -15,6 +15,7 @@ import logging
# Fuzzers known to lack a seed corpus in https://github.com/bitcoin-core/qa-assets/tree/master/fuzz_seed_corpus
FUZZERS_MISSING_CORPORA = [
"addr_info_deserialize",
+ "block",
"block_file_info_deserialize",
"block_filter_deserialize",
"block_header_and_short_txids_deserialize",