Skip to content

Commit 7726f3b

Browse files
tests: Add fuzzing harness for CFeeRate
1 parent 0579a27 commit 7726f3b

File tree

3 files changed

+76
-0
lines changed

3 files changed

+76
-0
lines changed

src/Makefile.test.include

+7
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ FUZZ_TARGETS = \
2929
test/fuzz/descriptor_parse \
3030
test/fuzz/diskblockindex_deserialize \
3131
test/fuzz/eval_script \
32+
test/fuzz/fee_rate \
3233
test/fuzz/fee_rate_deserialize \
3334
test/fuzz/flat_file_pos_deserialize \
3435
test/fuzz/float \
@@ -434,6 +435,12 @@ test_fuzz_eval_script_LDADD = $(FUZZ_SUITE_LD_COMMON)
434435
test_fuzz_eval_script_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
435436
test_fuzz_eval_script_SOURCES = $(FUZZ_SUITE) test/fuzz/eval_script.cpp
436437

438+
test_fuzz_fee_rate_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
439+
test_fuzz_fee_rate_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
440+
test_fuzz_fee_rate_LDADD = $(FUZZ_SUITE_LD_COMMON)
441+
test_fuzz_fee_rate_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
442+
test_fuzz_fee_rate_SOURCES = $(FUZZ_SUITE) test/fuzz/fee_rate.cpp
443+
437444
test_fuzz_fee_rate_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DFEE_RATE_DESERIALIZE=1
438445
test_fuzz_fee_rate_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
439446
test_fuzz_fee_rate_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)

src/test/fuzz/fee_rate.cpp

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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 <amount.h>
6+
#include <policy/feerate.h>
7+
#include <test/fuzz/FuzzedDataProvider.h>
8+
#include <test/fuzz/fuzz.h>
9+
#include <test/fuzz/util.h>
10+
11+
#include <cstdint>
12+
#include <limits>
13+
#include <string>
14+
#include <vector>
15+
16+
void test_one_input(const std::vector<uint8_t>& buffer)
17+
{
18+
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
19+
const CAmount satoshis_per_k = ConsumeMoney(fuzzed_data_provider);
20+
const CFeeRate fee_rate{satoshis_per_k};
21+
22+
(void)fee_rate.GetFeePerK();
23+
const size_t bytes = fuzzed_data_provider.ConsumeIntegral<size_t>();
24+
if (!MultiplicationOverflow(static_cast<int64_t>(bytes), satoshis_per_k) && bytes <= static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
25+
(void)fee_rate.GetFee(bytes);
26+
}
27+
(void)fee_rate.ToString();
28+
29+
const CAmount another_satoshis_per_k = ConsumeMoney(fuzzed_data_provider);
30+
CFeeRate larger_fee_rate{another_satoshis_per_k};
31+
larger_fee_rate += fee_rate;
32+
if (satoshis_per_k != 0 && another_satoshis_per_k != 0) {
33+
assert(fee_rate < larger_fee_rate);
34+
assert(!(fee_rate > larger_fee_rate));
35+
assert(!(fee_rate == larger_fee_rate));
36+
assert(fee_rate <= larger_fee_rate);
37+
assert(!(fee_rate >= larger_fee_rate));
38+
assert(fee_rate != larger_fee_rate);
39+
}
40+
}

src/test/fuzz/util.h

+29
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#ifndef BITCOIN_TEST_FUZZ_UTIL_H
66
#define BITCOIN_TEST_FUZZ_UTIL_H
77

8+
#include <amount.h>
89
#include <attributes.h>
910
#include <optional.h>
1011
#include <script/script.h>
@@ -43,6 +44,11 @@ NODISCARD inline opcodetype ConsumeOpcodeType(FuzzedDataProvider& fuzzed_data_pr
4344
return static_cast<opcodetype>(fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, MAX_OPCODE));
4445
}
4546

47+
NODISCARD inline CAmount ConsumeMoney(FuzzedDataProvider& fuzzed_data_provider) noexcept
48+
{
49+
return fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(0, MAX_MONEY);
50+
}
51+
4652
NODISCARD inline CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider) noexcept
4753
{
4854
const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
@@ -54,4 +60,27 @@ NODISCARD inline CScriptNum ConsumeScriptNum(FuzzedDataProvider& fuzzed_data_pro
5460
return CScriptNum{fuzzed_data_provider.ConsumeIntegral<int64_t>()};
5561
}
5662

63+
template <typename T>
64+
bool MultiplicationOverflow(T i, T j)
65+
{
66+
static_assert(std::is_integral<T>::value, "Integral required.");
67+
if (std::numeric_limits<T>::is_signed) {
68+
if (i > 0) {
69+
if (j > 0) {
70+
return i > (std::numeric_limits<T>::max() / j);
71+
} else {
72+
return j < (std::numeric_limits<T>::min() / i);
73+
}
74+
} else {
75+
if (j > 0) {
76+
return i < (std::numeric_limits<T>::min() / j);
77+
} else {
78+
return i != 0 && (j < (std::numeric_limits<T>::max() / i));
79+
}
80+
}
81+
} else {
82+
return j != 0 && i > std::numeric_limits<T>::max() / j;
83+
}
84+
}
85+
5786
#endif // BITCOIN_TEST_FUZZ_UTIL_H

0 commit comments

Comments
 (0)