diff options
author | MarcoFalke <falke.marco@gmail.com> | 2020-04-30 12:53:12 -0400 |
---|---|---|
committer | MarcoFalke <falke.marco@gmail.com> | 2020-04-30 12:53:42 -0400 |
commit | ef8ef31fd28acb1bac7566ac25202d95152a243e (patch) | |
tree | 5ac1314ac73b6d4190de633279b92764afbc03ac | |
parent | a66ba6d029b3948dec0cf092bb844f70c16b07dc (diff) | |
parent | 2bcc2bd742392730b4f21e3d4f00438c34acac1f (diff) |
Merge #18775: tests: Add fuzzing harnesses for various classes/functions in policy/ (CBlockPolicyEstimator, IsRBFOptIn(…), etc.)
2bcc2bd742392730b4f21e3d4f00438c34acac1f tests: Clarify how we avoid hitting the signed integer overflow in CFeeRate::GetFeePerK() when fuzzing (practicalswift)
13c1f6b24fa5e53f100d90d36b47b7dd3bc91b9f tests: Add fuzzing harness for IsRBFOptIn(...) (practicalswift)
3439c88a5d2d0bdcc30d949b9d400ca90b8a7d28 tests: Add fuzzing harness for CBlockPolicyEstimator (practicalswift)
Pull request description:
Add fuzzing harnesses for various classes/functions in `policy/` (`CBlockPolicyEstimator`, `IsRBFOptIn(…)`, etc.).
See [`doc/fuzzing.md`](https://github.com/bitcoin/bitcoin/blob/master/doc/fuzzing.md) for information on how to fuzz Bitcoin Core. Don't forget to contribute any coverage increasing inputs you find to the [Bitcoin Core fuzzing corpus repo](https://github.com/bitcoin-core/qa-assets).
Happy fuzzing :)
Top commit has no ACKs.
Tree-SHA512: a756687216802a3b260def5706798a1eb673b3447408561728af77a1d61c8bfb3a7d9b874e16bf619565e9d093f9b595e07d6e6fa430ac08dfeed4f45b01fbc3
-rw-r--r-- | src/Makefile.test.include | 14 | ||||
-rw-r--r-- | src/test/fuzz/policy_estimator.cpp | 69 | ||||
-rw-r--r-- | src/test/fuzz/rbf.cpp | 47 | ||||
-rw-r--r-- | src/test/fuzz/util.h | 18 |
4 files changed, 148 insertions, 0 deletions
diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 48db60f086..1fe4df8059 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -67,6 +67,7 @@ FUZZ_TARGETS = \ test/fuzz/parse_univalue \ test/fuzz/partial_merkle_tree_deserialize \ test/fuzz/partially_signed_transaction_deserialize \ + test/fuzz/policy_estimator \ test/fuzz/pow \ test/fuzz/prefilled_transaction_deserialize \ test/fuzz/prevector \ @@ -103,6 +104,7 @@ FUZZ_TARGETS = \ test/fuzz/psbt_output_deserialize \ test/fuzz/pub_key_deserialize \ test/fuzz/random \ + test/fuzz/rbf \ test/fuzz/rolling_bloom_filter \ test/fuzz/script \ test/fuzz/script_deserialize \ @@ -683,6 +685,12 @@ test_fuzz_partially_signed_transaction_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMO test_fuzz_partially_signed_transaction_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) test_fuzz_partially_signed_transaction_deserialize_SOURCES = test/fuzz/deserialize.cpp +test_fuzz_policy_estimator_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +test_fuzz_policy_estimator_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +test_fuzz_policy_estimator_LDADD = $(FUZZ_SUITE_LD_COMMON) +test_fuzz_policy_estimator_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) +test_fuzz_policy_estimator_SOURCES = test/fuzz/policy_estimator.cpp + test_fuzz_pow_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) test_fuzz_pow_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_pow_LDADD = $(FUZZ_SUITE_LD_COMMON) @@ -893,6 +901,12 @@ test_fuzz_random_LDADD = $(FUZZ_SUITE_LD_COMMON) test_fuzz_random_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) test_fuzz_random_SOURCES = test/fuzz/random.cpp +test_fuzz_rbf_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +test_fuzz_rbf_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +test_fuzz_rbf_LDADD = $(FUZZ_SUITE_LD_COMMON) +test_fuzz_rbf_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) +test_fuzz_rbf_SOURCES = test/fuzz/rbf.cpp + test_fuzz_rolling_bloom_filter_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) test_fuzz_rolling_bloom_filter_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_rolling_bloom_filter_LDADD = $(FUZZ_SUITE_LD_COMMON) diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp new file mode 100644 index 0000000000..201f49c87b --- /dev/null +++ b/src/test/fuzz/policy_estimator.cpp @@ -0,0 +1,69 @@ +// 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 <policy/fees.h> +#include <primitives/transaction.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/fuzz.h> +#include <test/fuzz/util.h> +#include <txmempool.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()); + CBlockPolicyEstimator block_policy_estimator; + while (fuzzed_data_provider.ConsumeBool()) { + switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 3)) { + case 0: { + const Optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider); + if (!mtx) { + break; + } + const CTransaction tx{*mtx}; + block_policy_estimator.processTransaction(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx), fuzzed_data_provider.ConsumeBool()); + if (fuzzed_data_provider.ConsumeBool()) { + (void)block_policy_estimator.removeTx(tx.GetHash(), /* inBlock */ fuzzed_data_provider.ConsumeBool()); + } + break; + } + case 1: { + std::vector<CTxMemPoolEntry> mempool_entries; + while (fuzzed_data_provider.ConsumeBool()) { + const Optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider); + if (!mtx) { + break; + } + const CTransaction tx{*mtx}; + mempool_entries.push_back(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx)); + } + std::vector<const CTxMemPoolEntry*> ptrs; + ptrs.reserve(mempool_entries.size()); + for (const CTxMemPoolEntry& mempool_entry : mempool_entries) { + ptrs.push_back(&mempool_entry); + } + block_policy_estimator.processBlock(fuzzed_data_provider.ConsumeIntegral<unsigned int>(), ptrs); + break; + } + case 2: { + (void)block_policy_estimator.removeTx(ConsumeUInt256(fuzzed_data_provider), /* inBlock */ fuzzed_data_provider.ConsumeBool()); + break; + } + case 3: { + block_policy_estimator.FlushUnconfirmed(); + break; + } + } + (void)block_policy_estimator.estimateFee(fuzzed_data_provider.ConsumeIntegral<int>()); + EstimationResult result; + (void)block_policy_estimator.estimateRawFee(fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeFloatingPoint<double>(), fuzzed_data_provider.PickValueInArray({FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}), fuzzed_data_provider.ConsumeBool() ? &result : nullptr); + FeeCalculation fee_calculation; + (void)block_policy_estimator.estimateSmartFee(fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeBool() ? &fee_calculation : nullptr, fuzzed_data_provider.ConsumeBool()); + (void)block_policy_estimator.HighestTargetTracked(fuzzed_data_provider.PickValueInArray({FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE})); + } +} diff --git a/src/test/fuzz/rbf.cpp b/src/test/fuzz/rbf.cpp new file mode 100644 index 0000000000..eb54b05df9 --- /dev/null +++ b/src/test/fuzz/rbf.cpp @@ -0,0 +1,47 @@ +// 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 <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 <txmempool.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()); + Optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider); + if (!mtx) { + return; + } + CTxMemPool pool; + while (fuzzed_data_provider.ConsumeBool()) { + const Optional<CMutableTransaction> another_mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider); + if (!another_mtx) { + break; + } + const CTransaction another_tx{*another_mtx}; + if (fuzzed_data_provider.ConsumeBool() && !mtx->vin.empty()) { + mtx->vin[0].prevout = COutPoint{another_tx.GetHash(), 0}; + } + LOCK2(cs_main, pool.cs); + pool.addUnchecked(ConsumeTxMemPoolEntry(fuzzed_data_provider, another_tx)); + } + const CTransaction tx{*mtx}; + if (fuzzed_data_provider.ConsumeBool()) { + LOCK2(cs_main, pool.cs); + pool.addUnchecked(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx)); + } + { + LOCK(pool.cs); + (void)IsRBFOptIn(tx, pool); + } +} diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h index 9c7b0d47a2..501bb1de5a 100644 --- a/src/test/fuzz/util.h +++ b/src/test/fuzz/util.h @@ -8,12 +8,15 @@ #include <amount.h> #include <arith_uint256.h> #include <attributes.h> +#include <consensus/consensus.h> #include <optional.h> +#include <primitives/transaction.h> #include <script/script.h> #include <serialize.h> #include <streams.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> +#include <txmempool.h> #include <uint256.h> #include <version.h> @@ -97,6 +100,21 @@ NODISCARD inline arith_uint256 ConsumeArithUInt256(FuzzedDataProvider& fuzzed_da return UintToArith256(ConsumeUInt256(fuzzed_data_provider)); } +NODISCARD inline CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept +{ + // Avoid: + // policy/feerate.cpp:28:34: runtime error: signed integer overflow: 34873208148477500 * 1000 cannot be represented in type 'long' + // + // Reproduce using CFeeRate(348732081484775, 10).GetFeePerK() + const CAmount fee = std::min<CAmount>(ConsumeMoney(fuzzed_data_provider), std::numeric_limits<CAmount>::max() / static_cast<CAmount>(100000)); + assert(MoneyRange(fee)); + const int64_t time = fuzzed_data_provider.ConsumeIntegral<int64_t>(); + const unsigned int entry_height = fuzzed_data_provider.ConsumeIntegral<unsigned int>(); + const bool spends_coinbase = fuzzed_data_provider.ConsumeBool(); + const unsigned int sig_op_cost = fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(0, MAX_BLOCK_SIGOPS_COST); + return CTxMemPoolEntry{MakeTransactionRef(tx), fee, time, entry_height, spends_coinbase, sig_op_cost, {}}; +} + template <typename T> NODISCARD bool MultiplicationOverflow(const T i, const T j) noexcept { |