aboutsummaryrefslogtreecommitdiff
path: root/src/test/fuzz
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/fuzz')
-rw-r--r--src/test/fuzz/node_eviction.cpp2
-rw-r--r--src/test/fuzz/policy_estimator.cpp8
-rw-r--r--src/test/fuzz/policy_estimator_io.cpp8
-rw-r--r--src/test/fuzz/rbf.cpp21
-rw-r--r--src/test/fuzz/rpc.cpp1
-rw-r--r--src/test/fuzz/tx_pool.cpp20
-rw-r--r--src/test/fuzz/txorphan.cpp143
-rw-r--r--src/test/fuzz/util.cpp53
-rw-r--r--src/test/fuzz/util.h6
-rw-r--r--src/test/fuzz/validation_load_mempool.cpp4
10 files changed, 258 insertions, 8 deletions
diff --git a/src/test/fuzz/node_eviction.cpp b/src/test/fuzz/node_eviction.cpp
index 6a363f00f7..e27b254580 100644
--- a/src/test/fuzz/node_eviction.cpp
+++ b/src/test/fuzz/node_eviction.cpp
@@ -32,6 +32,8 @@ FUZZ_TARGET(node_eviction)
/*prefer_evict=*/fuzzed_data_provider.ConsumeBool(),
/*m_is_local=*/fuzzed_data_provider.ConsumeBool(),
/*m_network=*/fuzzed_data_provider.PickValueInArray(ALL_NETWORKS),
+ /*m_noban=*/fuzzed_data_provider.ConsumeBool(),
+ /*m_conn_type=*/fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES),
});
}
// Make a copy since eviction_candidates may be in some valid but otherwise
diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp
index e4d95f72a0..58c19a91cb 100644
--- a/src/test/fuzz/policy_estimator.cpp
+++ b/src/test/fuzz/policy_estimator.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <policy/fees.h>
+#include <policy/fees_args.h>
#include <primitives/transaction.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
@@ -15,15 +16,20 @@
#include <string>
#include <vector>
+namespace {
+const BasicTestingSetup* g_setup;
+} // namespace
+
void initialize_policy_estimator()
{
static const auto testing_setup = MakeNoLogFileContext<>();
+ g_setup = testing_setup.get();
}
FUZZ_TARGET_INIT(policy_estimator, initialize_policy_estimator)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
- CBlockPolicyEstimator block_policy_estimator;
+ CBlockPolicyEstimator block_policy_estimator{FeeestPath(*g_setup->m_node.args)};
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
CallOneOf(
fuzzed_data_provider,
diff --git a/src/test/fuzz/policy_estimator_io.cpp b/src/test/fuzz/policy_estimator_io.cpp
index 9021d95954..77402c260a 100644
--- a/src/test/fuzz/policy_estimator_io.cpp
+++ b/src/test/fuzz/policy_estimator_io.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <policy/fees.h>
+#include <policy/fees_args.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
@@ -11,9 +12,14 @@
#include <cstdint>
#include <vector>
+namespace {
+const BasicTestingSetup* g_setup;
+} // namespace
+
void initialize_policy_estimator_io()
{
static const auto testing_setup = MakeNoLogFileContext<>();
+ g_setup = testing_setup.get();
}
FUZZ_TARGET_INIT(policy_estimator_io, initialize_policy_estimator_io)
@@ -22,7 +28,7 @@ FUZZ_TARGET_INIT(policy_estimator_io, initialize_policy_estimator_io)
FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider);
CAutoFile fuzzed_auto_file = fuzzed_auto_file_provider.open();
// Re-using block_policy_estimator across runs to avoid costly creation of CBlockPolicyEstimator object.
- static CBlockPolicyEstimator block_policy_estimator;
+ static CBlockPolicyEstimator block_policy_estimator{FeeestPath(*g_setup->m_node.args)};
if (block_policy_estimator.Read(fuzzed_auto_file)) {
block_policy_estimator.Write(fuzzed_auto_file);
}
diff --git a/src/test/fuzz/rbf.cpp b/src/test/fuzz/rbf.cpp
index 8dcaa609b5..4801635791 100644
--- a/src/test/fuzz/rbf.cpp
+++ b/src/test/fuzz/rbf.cpp
@@ -2,12 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <mempool_args.h>
#include <policy/rbf.h>
#include <primitives/transaction.h>
#include <sync.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
#include <txmempool.h>
#include <cstdint>
@@ -15,7 +17,17 @@
#include <string>
#include <vector>
-FUZZ_TARGET(rbf)
+namespace {
+const BasicTestingSetup* g_setup;
+} // namespace
+
+void initialize_rbf()
+{
+ static const auto testing_setup = MakeNoLogFileContext<>();
+ g_setup = testing_setup.get();
+}
+
+FUZZ_TARGET_INIT(rbf, initialize_rbf)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
SetMockTime(ConsumeTime(fuzzed_data_provider));
@@ -23,8 +35,11 @@ FUZZ_TARGET(rbf)
if (!mtx) {
return;
}
- CTxMemPool pool;
- LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
+
+ CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};
+
+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000)
+ {
const std::optional<CMutableTransaction> another_mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
if (!another_mtx) {
break;
diff --git a/src/test/fuzz/rpc.cpp b/src/test/fuzz/rpc.cpp
index e4e83c3f32..26913a41d2 100644
--- a/src/test/fuzz/rpc.cpp
+++ b/src/test/fuzz/rpc.cpp
@@ -159,6 +159,7 @@ const std::vector<std::string> RPC_COMMANDS_SAFE_FOR_FUZZING{
"signrawtransactionwithkey",
"submitblock",
"submitheader",
+ "submitpackage",
"syncwithvalidationinterfacequeue",
"testmempoolaccept",
"uptime",
diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp
index 4f40608c4f..2d88ee295b 100644
--- a/src/test/fuzz/tx_pool.cpp
+++ b/src/test/fuzz/tx_pool.cpp
@@ -3,6 +3,8 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <consensus/validation.h>
+#include <mempool_args.h>
+#include <node/context.h>
#include <node/miner.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
@@ -15,6 +17,7 @@
#include <validationinterface.h>
using node::BlockAssembler;
+using node::NodeContext;
namespace {
@@ -121,6 +124,19 @@ void MockTime(FuzzedDataProvider& fuzzed_data_provider, const CChainState& chain
SetMockTime(time);
}
+CTxMemPool MakeMempool(const NodeContext& node)
+{
+ // Take the default options for tests...
+ CTxMemPool::Options mempool_opts{MemPoolOptionsForTest(node)};
+
+ // ...override specific options for this specific fuzz suite
+ mempool_opts.estimator = nullptr;
+ mempool_opts.check_ratio = 1;
+
+ // ...and construct a CTxMemPool from it
+ return CTxMemPool{mempool_opts};
+}
+
FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
@@ -142,7 +158,7 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool)
// The sum of the values of all spendable outpoints
constexpr CAmount SUPPLY_TOTAL{COINBASE_MATURITY * 50 * COIN};
- CTxMemPool tx_pool_{/*estimator=*/nullptr, /*check_ratio=*/1};
+ CTxMemPool tx_pool_{MakeMempool(node)};
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_);
chainstate.SetMempool(&tx_pool);
@@ -320,7 +336,7 @@ FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool)
txids.push_back(ConsumeUInt256(fuzzed_data_provider));
}
- CTxMemPool tx_pool_{/*estimator=*/nullptr, /*check_ratio=*/1};
+ CTxMemPool tx_pool_{MakeMempool(node)};
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_);
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 300)
diff --git a/src/test/fuzz/txorphan.cpp b/src/test/fuzz/txorphan.cpp
new file mode 100644
index 0000000000..d318baa6a2
--- /dev/null
+++ b/src/test/fuzz/txorphan.cpp
@@ -0,0 +1,143 @@
+// Copyright (c) 2022 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 <consensus/amount.h>
+#include <net.h>
+#include <net_processing.h>
+#include <primitives/transaction.h>
+#include <script/script.h>
+#include <sync.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
+#include <txorphanage.h>
+#include <uint256.h>
+#include <util/check.h>
+#include <util/time.h>
+
+#include <algorithm>
+#include <cstdint>
+#include <memory>
+#include <set>
+#include <utility>
+#include <vector>
+
+void initialize_orphanage()
+{
+ static const auto testing_setup = MakeNoLogFileContext();
+}
+
+FUZZ_TARGET_INIT(txorphan, initialize_orphanage)
+{
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+ SetMockTime(ConsumeTime(fuzzed_data_provider));
+
+ TxOrphanage orphanage;
+ std::set<uint256> orphan_work_set;
+ std::vector<COutPoint> outpoints;
+ // initial outpoints used to construct transactions later
+ for (uint8_t i = 0; i < 4; i++) {
+ outpoints.emplace_back(uint256{i}, 0);
+ }
+ // if true, allow duplicate input when constructing tx
+ const bool duplicate_input = fuzzed_data_provider.ConsumeBool();
+
+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10 * DEFAULT_MAX_ORPHAN_TRANSACTIONS)
+ {
+ // construct transaction
+ const CTransactionRef tx = [&] {
+ CMutableTransaction tx_mut;
+ const auto num_in = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(1, outpoints.size());
+ const auto num_out = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(1, outpoints.size());
+ // pick unique outpoints from outpoints as input
+ for (uint32_t i = 0; i < num_in; i++) {
+ auto& prevout = PickValue(fuzzed_data_provider, outpoints);
+ tx_mut.vin.emplace_back(prevout);
+ // pop the picked outpoint if duplicate input is not allowed
+ if (!duplicate_input) {
+ std::swap(prevout, outpoints.back());
+ outpoints.pop_back();
+ }
+ }
+ // output amount will not affect txorphanage
+ for (uint32_t i = 0; i < num_out; i++) {
+ tx_mut.vout.emplace_back(CAmount{0}, CScript{});
+ }
+ // restore previously poped outpoints
+ for (auto& in : tx_mut.vin) {
+ outpoints.push_back(in.prevout);
+ }
+ const auto new_tx = MakeTransactionRef(tx_mut);
+ // add newly constructed transaction to outpoints
+ for (uint32_t i = 0; i < num_out; i++) {
+ outpoints.emplace_back(new_tx->GetHash(), i);
+ }
+ return new_tx;
+ }();
+
+ // trigger orphanage functions
+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10 * DEFAULT_MAX_ORPHAN_TRANSACTIONS)
+ {
+ NodeId peer_id = fuzzed_data_provider.ConsumeIntegral<NodeId>();
+
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ LOCK(g_cs_orphans);
+ orphanage.AddChildrenToWorkSet(*tx, orphan_work_set);
+ },
+ [&] {
+ bool have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
+ {
+ LOCK(g_cs_orphans);
+ bool get_tx = orphanage.GetTx(tx->GetHash()).first != nullptr;
+ Assert(have_tx == get_tx);
+ }
+ },
+ [&] {
+ bool have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
+ // AddTx should return false if tx is too big or already have it
+ {
+ LOCK(g_cs_orphans);
+ Assert(have_tx != orphanage.AddTx(tx, peer_id));
+ }
+ have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
+ // tx should already be added since it will not be too big in the test
+ // have_tx should be true and AddTx should fail
+ {
+ LOCK(g_cs_orphans);
+ Assert(have_tx && !orphanage.AddTx(tx, peer_id));
+ }
+ },
+ [&] {
+ bool have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
+ // EraseTx should return 0 if m_orphans doesn't have the tx
+ {
+ LOCK(g_cs_orphans);
+ Assert(have_tx == orphanage.EraseTx(tx->GetHash()));
+ }
+ have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
+ // have_tx should be false and EraseTx should fail
+ {
+ LOCK(g_cs_orphans);
+ Assert(!have_tx && !orphanage.EraseTx(tx->GetHash()));
+ }
+ },
+ [&] {
+ LOCK(g_cs_orphans);
+ orphanage.EraseForPeer(peer_id);
+ },
+ [&] {
+ // test mocktime and expiry
+ SetMockTime(ConsumeTime(fuzzed_data_provider));
+ auto size_before = orphanage.Size();
+ auto limit = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
+ auto n_evicted = WITH_LOCK(g_cs_orphans, return orphanage.LimitOrphans(limit));
+ Assert(size_before - n_evicted <= limit);
+ Assert(orphanage.Size() <= limit);
+ });
+ }
+ }
+}
diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp
index 8f5e771e37..4b893c648e 100644
--- a/src/test/fuzz/util.cpp
+++ b/src/test/fuzz/util.cpp
@@ -155,6 +155,45 @@ int FuzzedSock::Connect(const sockaddr*, socklen_t) const
return 0;
}
+int FuzzedSock::Bind(const sockaddr*, socklen_t) const
+{
+ // Have a permanent error at bind_errnos[0] because when the fuzzed data is exhausted
+ // SetFuzzedErrNo() will always set the global errno to bind_errnos[0]. We want to
+ // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
+ // repeatedly because proper code should retry on temporary errors, leading to an
+ // infinite loop.
+ constexpr std::array bind_errnos{
+ EACCES,
+ EADDRINUSE,
+ EADDRNOTAVAIL,
+ EAGAIN,
+ };
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, bind_errnos);
+ return -1;
+ }
+ return 0;
+}
+
+int FuzzedSock::Listen(int) const
+{
+ // Have a permanent error at listen_errnos[0] because when the fuzzed data is exhausted
+ // SetFuzzedErrNo() will always set the global errno to listen_errnos[0]. We want to
+ // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
+ // repeatedly because proper code should retry on temporary errors, leading to an
+ // infinite loop.
+ constexpr std::array listen_errnos{
+ EADDRINUSE,
+ EINVAL,
+ EOPNOTSUPP,
+ };
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, listen_errnos);
+ return -1;
+ }
+ return 0;
+}
+
std::unique_ptr<Sock> FuzzedSock::Accept(sockaddr* addr, socklen_t* addr_len) const
{
constexpr std::array accept_errnos{
@@ -201,6 +240,20 @@ int FuzzedSock::SetSockOpt(int, int, const void*, socklen_t) const
return 0;
}
+int FuzzedSock::GetSockName(sockaddr* name, socklen_t* name_len) const
+{
+ constexpr std::array getsockname_errnos{
+ ECONNRESET,
+ ENOBUFS,
+ };
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, getsockname_errnos);
+ return -1;
+ }
+ *name_len = m_fuzzed_data_provider.ConsumeData(name, *name_len);
+ return 0;
+}
+
bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
{
constexpr std::array wait_errnos{
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index 0819d326fd..4b89ad9bdc 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -61,12 +61,18 @@ public:
int Connect(const sockaddr*, socklen_t) const override;
+ int Bind(const sockaddr*, socklen_t) const override;
+
+ int Listen(int backlog) const override;
+
std::unique_ptr<Sock> Accept(sockaddr* addr, socklen_t* addr_len) const override;
int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override;
int SetSockOpt(int level, int opt_name, const void* opt_val, socklen_t opt_len) const override;
+ int GetSockName(sockaddr* name, socklen_t* name_len) const override;
+
bool Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred = nullptr) const override;
bool WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const override;
diff --git a/src/test/fuzz/validation_load_mempool.cpp b/src/test/fuzz/validation_load_mempool.cpp
index c2aaf486c5..9532610f8d 100644
--- a/src/test/fuzz/validation_load_mempool.cpp
+++ b/src/test/fuzz/validation_load_mempool.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chainparamsbase.h>
+#include <mempool_args.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
@@ -30,7 +31,8 @@ FUZZ_TARGET_INIT(validation_load_mempool, initialize_validation_load_mempool)
SetMockTime(ConsumeTime(fuzzed_data_provider));
FuzzedFileProvider fuzzed_file_provider = ConsumeFile(fuzzed_data_provider);
- CTxMemPool pool{};
+ CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};
+
auto fuzzed_fopen = [&](const fs::path&, const char*) {
return fuzzed_file_provider.open();
};