Skip to content

Commit ef8ef31

Browse files
author
MarcoFalke
committed
Merge #18775: tests: Add fuzzing harnesses for various classes/functions in policy/ (CBlockPolicyEstimator, IsRBFOptIn(…), etc.)
2bcc2bd tests: Clarify how we avoid hitting the signed integer overflow in CFeeRate::GetFeePerK() when fuzzing (practicalswift) 13c1f6b tests: Add fuzzing harness for IsRBFOptIn(...) (practicalswift) 3439c88 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
2 parents a66ba6d + 2bcc2bd commit ef8ef31

File tree

4 files changed

+148
-0
lines changed

4 files changed

+148
-0
lines changed

src/Makefile.test.include

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ FUZZ_TARGETS = \
6767
test/fuzz/parse_univalue \
6868
test/fuzz/partial_merkle_tree_deserialize \
6969
test/fuzz/partially_signed_transaction_deserialize \
70+
test/fuzz/policy_estimator \
7071
test/fuzz/pow \
7172
test/fuzz/prefilled_transaction_deserialize \
7273
test/fuzz/prevector \
@@ -103,6 +104,7 @@ FUZZ_TARGETS = \
103104
test/fuzz/psbt_output_deserialize \
104105
test/fuzz/pub_key_deserialize \
105106
test/fuzz/random \
107+
test/fuzz/rbf \
106108
test/fuzz/rolling_bloom_filter \
107109
test/fuzz/script \
108110
test/fuzz/script_deserialize \
@@ -683,6 +685,12 @@ test_fuzz_partially_signed_transaction_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMO
683685
test_fuzz_partially_signed_transaction_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
684686
test_fuzz_partially_signed_transaction_deserialize_SOURCES = test/fuzz/deserialize.cpp
685687

688+
test_fuzz_policy_estimator_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
689+
test_fuzz_policy_estimator_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
690+
test_fuzz_policy_estimator_LDADD = $(FUZZ_SUITE_LD_COMMON)
691+
test_fuzz_policy_estimator_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
692+
test_fuzz_policy_estimator_SOURCES = test/fuzz/policy_estimator.cpp
693+
686694
test_fuzz_pow_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
687695
test_fuzz_pow_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
688696
test_fuzz_pow_LDADD = $(FUZZ_SUITE_LD_COMMON)
@@ -893,6 +901,12 @@ test_fuzz_random_LDADD = $(FUZZ_SUITE_LD_COMMON)
893901
test_fuzz_random_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
894902
test_fuzz_random_SOURCES = test/fuzz/random.cpp
895903

904+
test_fuzz_rbf_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
905+
test_fuzz_rbf_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
906+
test_fuzz_rbf_LDADD = $(FUZZ_SUITE_LD_COMMON)
907+
test_fuzz_rbf_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
908+
test_fuzz_rbf_SOURCES = test/fuzz/rbf.cpp
909+
896910
test_fuzz_rolling_bloom_filter_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
897911
test_fuzz_rolling_bloom_filter_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
898912
test_fuzz_rolling_bloom_filter_LDADD = $(FUZZ_SUITE_LD_COMMON)

src/test/fuzz/policy_estimator.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright (c) 2020 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <optional.h>
6+
#include <policy/fees.h>
7+
#include <primitives/transaction.h>
8+
#include <test/fuzz/FuzzedDataProvider.h>
9+
#include <test/fuzz/fuzz.h>
10+
#include <test/fuzz/util.h>
11+
#include <txmempool.h>
12+
13+
#include <cstdint>
14+
#include <string>
15+
#include <vector>
16+
17+
void test_one_input(const std::vector<uint8_t>& buffer)
18+
{
19+
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
20+
CBlockPolicyEstimator block_policy_estimator;
21+
while (fuzzed_data_provider.ConsumeBool()) {
22+
switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 3)) {
23+
case 0: {
24+
const Optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
25+
if (!mtx) {
26+
break;
27+
}
28+
const CTransaction tx{*mtx};
29+
block_policy_estimator.processTransaction(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx), fuzzed_data_provider.ConsumeBool());
30+
if (fuzzed_data_provider.ConsumeBool()) {
31+
(void)block_policy_estimator.removeTx(tx.GetHash(), /* inBlock */ fuzzed_data_provider.ConsumeBool());
32+
}
33+
break;
34+
}
35+
case 1: {
36+
std::vector<CTxMemPoolEntry> mempool_entries;
37+
while (fuzzed_data_provider.ConsumeBool()) {
38+
const Optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
39+
if (!mtx) {
40+
break;
41+
}
42+
const CTransaction tx{*mtx};
43+
mempool_entries.push_back(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx));
44+
}
45+
std::vector<const CTxMemPoolEntry*> ptrs;
46+
ptrs.reserve(mempool_entries.size());
47+
for (const CTxMemPoolEntry& mempool_entry : mempool_entries) {
48+
ptrs.push_back(&mempool_entry);
49+
}
50+
block_policy_estimator.processBlock(fuzzed_data_provider.ConsumeIntegral<unsigned int>(), ptrs);
51+
break;
52+
}
53+
case 2: {
54+
(void)block_policy_estimator.removeTx(ConsumeUInt256(fuzzed_data_provider), /* inBlock */ fuzzed_data_provider.ConsumeBool());
55+
break;
56+
}
57+
case 3: {
58+
block_policy_estimator.FlushUnconfirmed();
59+
break;
60+
}
61+
}
62+
(void)block_policy_estimator.estimateFee(fuzzed_data_provider.ConsumeIntegral<int>());
63+
EstimationResult result;
64+
(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);
65+
FeeCalculation fee_calculation;
66+
(void)block_policy_estimator.estimateSmartFee(fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeBool() ? &fee_calculation : nullptr, fuzzed_data_provider.ConsumeBool());
67+
(void)block_policy_estimator.HighestTargetTracked(fuzzed_data_provider.PickValueInArray({FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}));
68+
}
69+
}

src/test/fuzz/rbf.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (c) 2020 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <optional.h>
6+
#include <policy/rbf.h>
7+
#include <primitives/transaction.h>
8+
#include <sync.h>
9+
#include <test/fuzz/FuzzedDataProvider.h>
10+
#include <test/fuzz/fuzz.h>
11+
#include <test/fuzz/util.h>
12+
#include <txmempool.h>
13+
14+
#include <cstdint>
15+
#include <string>
16+
#include <vector>
17+
18+
void test_one_input(const std::vector<uint8_t>& buffer)
19+
{
20+
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
21+
Optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
22+
if (!mtx) {
23+
return;
24+
}
25+
CTxMemPool pool;
26+
while (fuzzed_data_provider.ConsumeBool()) {
27+
const Optional<CMutableTransaction> another_mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
28+
if (!another_mtx) {
29+
break;
30+
}
31+
const CTransaction another_tx{*another_mtx};
32+
if (fuzzed_data_provider.ConsumeBool() && !mtx->vin.empty()) {
33+
mtx->vin[0].prevout = COutPoint{another_tx.GetHash(), 0};
34+
}
35+
LOCK2(cs_main, pool.cs);
36+
pool.addUnchecked(ConsumeTxMemPoolEntry(fuzzed_data_provider, another_tx));
37+
}
38+
const CTransaction tx{*mtx};
39+
if (fuzzed_data_provider.ConsumeBool()) {
40+
LOCK2(cs_main, pool.cs);
41+
pool.addUnchecked(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx));
42+
}
43+
{
44+
LOCK(pool.cs);
45+
(void)IsRBFOptIn(tx, pool);
46+
}
47+
}

src/test/fuzz/util.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,15 @@
88
#include <amount.h>
99
#include <arith_uint256.h>
1010
#include <attributes.h>
11+
#include <consensus/consensus.h>
1112
#include <optional.h>
13+
#include <primitives/transaction.h>
1214
#include <script/script.h>
1315
#include <serialize.h>
1416
#include <streams.h>
1517
#include <test/fuzz/FuzzedDataProvider.h>
1618
#include <test/fuzz/fuzz.h>
19+
#include <txmempool.h>
1720
#include <uint256.h>
1821
#include <version.h>
1922

@@ -97,6 +100,21 @@ NODISCARD inline arith_uint256 ConsumeArithUInt256(FuzzedDataProvider& fuzzed_da
97100
return UintToArith256(ConsumeUInt256(fuzzed_data_provider));
98101
}
99102

103+
NODISCARD inline CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept
104+
{
105+
// Avoid:
106+
// policy/feerate.cpp:28:34: runtime error: signed integer overflow: 34873208148477500 * 1000 cannot be represented in type 'long'
107+
//
108+
// Reproduce using CFeeRate(348732081484775, 10).GetFeePerK()
109+
const CAmount fee = std::min<CAmount>(ConsumeMoney(fuzzed_data_provider), std::numeric_limits<CAmount>::max() / static_cast<CAmount>(100000));
110+
assert(MoneyRange(fee));
111+
const int64_t time = fuzzed_data_provider.ConsumeIntegral<int64_t>();
112+
const unsigned int entry_height = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
113+
const bool spends_coinbase = fuzzed_data_provider.ConsumeBool();
114+
const unsigned int sig_op_cost = fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(0, MAX_BLOCK_SIGOPS_COST);
115+
return CTxMemPoolEntry{MakeTransactionRef(tx), fee, time, entry_height, spends_coinbase, sig_op_cost, {}};
116+
}
117+
100118
template <typename T>
101119
NODISCARD bool MultiplicationOverflow(const T i, const T j) noexcept
102120
{

0 commit comments

Comments
 (0)