Skip to content

Commit 6eb0909

Browse files
committed
fuzz: add low-level target for txorphanage
1 parent b9122e9 commit 6eb0909

File tree

3 files changed

+145
-0
lines changed

3 files changed

+145
-0
lines changed

ci/test/06_script_b.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ if [ "${RUN_TIDY}" = "true" ]; then
4646
" src/policy/settings.cpp"\
4747
" src/rpc/fees.cpp"\
4848
" src/rpc/signmessage.cpp"\
49+
" src/test/fuzz/txorphan.cpp"\
4950
" -p . ${MAKEJOBS} -- -Xiwyu --cxx17ns -Xiwyu --mapping_file=${BASE_BUILD_DIR}/bitcoin-$HOST/contrib/devtools/iwyu/bitcoin.core.imp"
5051
fi
5152

src/Makefile.test.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ test_fuzz_fuzz_SOURCES = \
325325
test/fuzz/tx_in.cpp \
326326
test/fuzz/tx_out.cpp \
327327
test/fuzz/tx_pool.cpp \
328+
test/fuzz/txorphan.cpp \
328329
test/fuzz/txrequest.cpp \
329330
test/fuzz/utxo_snapshot.cpp \
330331
test/fuzz/validation_load_mempool.cpp \

src/test/fuzz/txorphan.cpp

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
// Copyright (c) 2022 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 <consensus/amount.h>
6+
#include <net.h>
7+
#include <net_processing.h>
8+
#include <primitives/transaction.h>
9+
#include <script/script.h>
10+
#include <sync.h>
11+
#include <test/fuzz/FuzzedDataProvider.h>
12+
#include <test/fuzz/fuzz.h>
13+
#include <test/fuzz/util.h>
14+
#include <test/util/setup_common.h>
15+
#include <txorphanage.h>
16+
#include <uint256.h>
17+
#include <util/check.h>
18+
#include <util/time.h>
19+
20+
#include <algorithm>
21+
#include <cstdint>
22+
#include <memory>
23+
#include <set>
24+
#include <utility>
25+
#include <vector>
26+
27+
void initialize_orphanage()
28+
{
29+
static const auto testing_setup = MakeNoLogFileContext();
30+
}
31+
32+
FUZZ_TARGET_INIT(txorphan, initialize_orphanage)
33+
{
34+
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
35+
SetMockTime(ConsumeTime(fuzzed_data_provider));
36+
37+
TxOrphanage orphanage;
38+
std::set<uint256> orphan_work_set;
39+
std::vector<COutPoint> outpoints;
40+
// initial outpoints used to construct transactions later
41+
for (uint8_t i = 0; i < 4; i++) {
42+
outpoints.emplace_back(uint256{i}, 0);
43+
}
44+
// if true, allow duplicate input when constructing tx
45+
const bool duplicate_input = fuzzed_data_provider.ConsumeBool();
46+
47+
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10 * DEFAULT_MAX_ORPHAN_TRANSACTIONS)
48+
{
49+
// construct transaction
50+
const CTransactionRef tx = [&] {
51+
CMutableTransaction tx_mut;
52+
const auto num_in = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(1, outpoints.size());
53+
const auto num_out = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(1, outpoints.size());
54+
// pick unique outpoints from outpoints as input
55+
for (uint32_t i = 0; i < num_in; i++) {
56+
auto& prevout = PickValue(fuzzed_data_provider, outpoints);
57+
tx_mut.vin.emplace_back(prevout);
58+
// pop the picked outpoint if duplicate input is not allowed
59+
if (!duplicate_input) {
60+
std::swap(prevout, outpoints.back());
61+
outpoints.pop_back();
62+
}
63+
}
64+
// output amount will not affect txorphanage
65+
for (uint32_t i = 0; i < num_out; i++) {
66+
tx_mut.vout.emplace_back(CAmount{0}, CScript{});
67+
}
68+
// restore previously poped outpoints
69+
for (auto& in : tx_mut.vin) {
70+
outpoints.push_back(in.prevout);
71+
}
72+
const auto new_tx = MakeTransactionRef(tx_mut);
73+
// add newly constructed transaction to outpoints
74+
for (uint32_t i = 0; i < num_out; i++) {
75+
outpoints.emplace_back(new_tx->GetHash(), i);
76+
}
77+
return new_tx;
78+
}();
79+
80+
// trigger orphanage functions
81+
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10 * DEFAULT_MAX_ORPHAN_TRANSACTIONS)
82+
{
83+
NodeId peer_id = fuzzed_data_provider.ConsumeIntegral<NodeId>();
84+
85+
CallOneOf(
86+
fuzzed_data_provider,
87+
[&] {
88+
LOCK(g_cs_orphans);
89+
orphanage.AddChildrenToWorkSet(*tx, orphan_work_set);
90+
},
91+
[&] {
92+
bool have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
93+
{
94+
LOCK(g_cs_orphans);
95+
bool get_tx = orphanage.GetTx(tx->GetHash()).first != nullptr;
96+
Assert(have_tx == get_tx);
97+
}
98+
},
99+
[&] {
100+
bool have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
101+
// AddTx should return false if tx is too big or already have it
102+
{
103+
LOCK(g_cs_orphans);
104+
Assert(have_tx != orphanage.AddTx(tx, peer_id));
105+
}
106+
have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
107+
// tx should already be added since it will not be too big in the test
108+
// have_tx should be true and AddTx should fail
109+
{
110+
LOCK(g_cs_orphans);
111+
Assert(have_tx && !orphanage.AddTx(tx, peer_id));
112+
}
113+
},
114+
[&] {
115+
bool have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
116+
// EraseTx should return 0 if m_orphans doesn't have the tx
117+
{
118+
LOCK(g_cs_orphans);
119+
Assert(have_tx == orphanage.EraseTx(tx->GetHash()));
120+
}
121+
have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
122+
// have_tx should be false and EraseTx should fail
123+
{
124+
LOCK(g_cs_orphans);
125+
Assert(!have_tx && !orphanage.EraseTx(tx->GetHash()));
126+
}
127+
},
128+
[&] {
129+
LOCK(g_cs_orphans);
130+
orphanage.EraseForPeer(peer_id);
131+
},
132+
[&] {
133+
// test mocktime and expiry
134+
SetMockTime(ConsumeTime(fuzzed_data_provider));
135+
auto size_before = orphanage.Size();
136+
auto limit = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
137+
auto n_evicted = WITH_LOCK(g_cs_orphans, return orphanage.LimitOrphans(limit));
138+
Assert(size_before - n_evicted <= limit);
139+
Assert(orphanage.Size() <= limit);
140+
});
141+
}
142+
}
143+
}

0 commit comments

Comments
 (0)