Skip to content

Commit d0bf9bb

Browse files
author
MarcoFalke
committed
Merge bitcoin/bitcoin#23373: test: Parse command line arguments from unit and fuzz tests, make addrman consistency check ratio easier to change
7f122a4 fuzz: non-addrman fuzz tests: override-able check ratio (Vasil Dimov) 3bd83e2 fuzz: addrman fuzz tests: override-able check ratio (Vasil Dimov) 46b0fe7 test: non-addrman unit tests: override-able check ratio (Vasil Dimov) 81e4d54 test: addrman unit tests: override-able check ratio (Vasil Dimov) 6dff621 bench: put addrman check ratio in a variable (Vasil Dimov) 6f7c756 fuzz: parse the command line arguments in fuzz tests (Vasil Dimov) 92a0f7e test: parse the command line arguments in unit tests (Vasil Dimov) Pull request description: Previously command line arguments passed to unit and fuzz tests would be ignored by the tests themselves. They would be used by the boost test framework (e.g. `--run_test="addrman_tests/*"`) or by the fuzzer (e.g. `-runs=1`). However both provide ways to pass down the extra arguments to the test itself. Use that, parse the arguments and make them available to the tests via `gArgs`. This makes the tests more flexible as they can be run with any bitcoind config option specified on the command line. When creating `AddrMan` objects in tests, use `-checkaddrman=` (if provided) instead of hardcoding the check ratio in many different places. See bitcoin/bitcoin#20233 (comment) for further motivation for this. ACKs for top commit: mzumsande: re-ACK 7f122a4 josibake: reACK bitcoin/bitcoin@7f122a4 Tree-SHA512: 3a05e61e4d70a0569bb67594bcce3aad8fdef63cdcc54e2823a3bc9f18679571985004412b6c332a210f67849bab32d8467b4115fbff8f5fac9834982e60dcf3
2 parents 427e9c9 + 7f122a4 commit d0bf9bb

File tree

13 files changed

+170
-55
lines changed

13 files changed

+170
-55
lines changed

doc/fuzzing.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@ block^@M-^?M-^?M-^?M-^?M-^?nM-^?M-^?
7171
7272
In this case the fuzzer managed to create a `block` message which when passed to `ProcessMessage(...)` increased coverage.
7373
74+
It is possible to specify `bitcoind` arguments to the `fuzz` executable.
75+
Depending on the test, they may be ignored or consumed and alter the behavior
76+
of the test. Just make sure to use double-dash to distinguish them from the
77+
fuzzer's own arguments:
78+
79+
```sh
80+
$ FUZZ=address_deserialize_v2 src/test/fuzz/fuzz -runs=1 fuzz_seed_corpus/address_deserialize_v2 --checkaddrman=5 --printtoconsole=1
81+
```
82+
7483
## Fuzzing corpora
7584
7685
The project's collection of seed corpora is found in the [`bitcoin-core/qa-assets`](https://github.com/bitcoin-core/qa-assets) repo.

src/bench/addrman.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
static constexpr size_t NUM_SOURCES = 64;
1717
static constexpr size_t NUM_ADDRESSES_PER_SOURCE = 256;
1818

19+
static const std::vector<bool> EMPTY_ASMAP;
20+
static constexpr uint32_t ADDRMAN_CONSISTENCY_CHECK_RATIO{0};
21+
1922
static std::vector<CAddress> g_sources;
2023
static std::vector<std::vector<CAddress>> g_addresses;
2124

@@ -74,14 +77,14 @@ static void AddrManAdd(benchmark::Bench& bench)
7477
CreateAddresses();
7578

7679
bench.run([&] {
77-
AddrMan addrman{/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0};
80+
AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
7881
AddAddressesToAddrMan(addrman);
7982
});
8083
}
8184

8285
static void AddrManSelect(benchmark::Bench& bench)
8386
{
84-
AddrMan addrman(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0);
87+
AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
8588

8689
FillAddrMan(addrman);
8790

@@ -93,7 +96,7 @@ static void AddrManSelect(benchmark::Bench& bench)
9396

9497
static void AddrManGetAddr(benchmark::Bench& bench)
9598
{
96-
AddrMan addrman(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0);
99+
AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
97100

98101
FillAddrMan(addrman);
99102

@@ -122,7 +125,7 @@ static void AddrManAddThenGood(benchmark::Bench& bench)
122125
//
123126
// This has some overhead (exactly the result of AddrManAdd benchmark), but that overhead is constant so improvements in
124127
// AddrMan::Good() will still be noticeable.
125-
AddrMan addrman(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0);
128+
AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
126129
AddAddressesToAddrMan(addrman);
127130

128131
markSomeAsGood(addrman);

src/bench/bench.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ using namespace std::chrono_literals;
1919

2020
const std::function<void(const std::string&)> G_TEST_LOG_FUN{};
2121

22+
const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUMENTS{};
23+
2224
namespace {
2325

2426
void GenerateTemplateResults(const std::vector<ankerl::nanobench::Result>& benchmarkResults, const std::string& filename, const char* tpl)

src/qt/test/test_main.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <QApplication>
2323
#include <QObject>
2424
#include <QTest>
25+
#include <functional>
2526

2627
#if defined(QT_STATICPLUGIN)
2728
#include <QtPlugin>
@@ -43,6 +44,8 @@ using node::NodeContext;
4344

4445
const std::function<void(const std::string&)> G_TEST_LOG_FUN{};
4546

47+
const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUMENTS{};
48+
4649
// This is all you need to run all the tests
4750
int main(int argc, char* argv[])
4851
{

src/test/README.md

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,31 @@ the `src/qt/test/test_main.cpp` file.
3333

3434
### Running individual tests
3535

36-
`test_bitcoin` has some built-in command-line arguments; for
37-
example, to run just the `getarg_tests` verbosely:
36+
`test_bitcoin` accepts the command line arguments from the boost framework.
37+
For example, to run just the `getarg_tests` suite of tests:
3838

39-
test_bitcoin --log_level=all --run_test=getarg_tests -- DEBUG_LOG_OUT
39+
```bash
40+
test_bitcoin --log_level=all --run_test=getarg_tests
41+
```
4042

4143
`log_level` controls the verbosity of the test framework, which logs when a
42-
test case is entered, for example. The `DEBUG_LOG_OUT` after the two dashes
43-
redirects the debug log, which would normally go to a file in the test datadir
44+
test case is entered, for example. `test_bitcoin` also accepts the command
45+
line arguments accepted by `bitcoind`. Use `--` to separate both types of
46+
arguments:
47+
48+
```bash
49+
test_bitcoin --log_level=all --run_test=getarg_tests -- -printtoconsole=1
50+
```
51+
52+
The `-printtoconsole=1` after the two dashes redirects the debug log, which
53+
would normally go to a file in the test datadir
4454
(`BasicTestingSetup::m_path_root`), to the standard terminal output.
4555

4656
... or to run just the doubledash test:
4757

48-
test_bitcoin --run_test=getarg_tests/doubledash
58+
```bash
59+
test_bitcoin --run_test=getarg_tests/doubledash
60+
```
4961

5062
Run `test_bitcoin --help` for the full list.
5163

@@ -68,7 +80,7 @@ on failure. For running individual tests verbosely, refer to the section
6880
To write to logs from unit tests you need to use specific message methods
6981
provided by Boost. The simplest is `BOOST_TEST_MESSAGE`.
7082

71-
For debugging you can launch the `test_bitcoin` executable with `gdb`or `lldb` and
83+
For debugging you can launch the `test_bitcoin` executable with `gdb` or `lldb` and
7284
start debugging, just like you would with any other program:
7385

7486
```bash
@@ -95,7 +107,7 @@ Running the tests and hitting a segmentation fault should now produce a file cal
95107
`/proc/sys/kernel/core_pattern`).
96108

97109
You can then explore the core dump using
98-
``` bash
110+
```bash
99111
gdb src/test/test_bitcoin core
100112

101113
(gbd) bt # produce a backtrace for where a segfault occurred

src/test/addrman_tests.cpp

Lines changed: 37 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@
2121
#include <string>
2222

2323
using namespace std::literals;
24+
using node::NodeContext;
25+
26+
static const std::vector<bool> EMPTY_ASMAP;
27+
static const bool DETERMINISTIC{true};
28+
29+
static int32_t GetCheckRatio(const NodeContext& node_ctx)
30+
{
31+
return std::clamp<int32_t>(node_ctx.args->GetIntArg("-checkaddrman", 100), 0, 1000000);
32+
}
2433

2534
static CNetAddr ResolveIP(const std::string& ip)
2635
{
@@ -49,17 +58,11 @@ static std::vector<bool> FromBytes(const unsigned char* source, int vector_size)
4958
return result;
5059
}
5160

52-
/* Utility function to create a deterministic addrman, as used in most tests */
53-
static std::unique_ptr<AddrMan> TestAddrMan(std::vector<bool> asmap = std::vector<bool>())
54-
{
55-
return std::make_unique<AddrMan>(asmap, /*deterministic=*/true, /*consistency_check_ratio=*/100);
56-
}
57-
5861
BOOST_FIXTURE_TEST_SUITE(addrman_tests, BasicTestingSetup)
5962

6063
BOOST_AUTO_TEST_CASE(addrman_simple)
6164
{
62-
auto addrman = TestAddrMan();
65+
auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
6366

6467
CNetAddr source = ResolveIP("252.2.2.2");
6568

@@ -93,7 +96,7 @@ BOOST_AUTO_TEST_CASE(addrman_simple)
9396
BOOST_CHECK(addrman->size() >= 1);
9497

9598
// Test: reset addrman and test AddrMan::Add multiple addresses works as expected
96-
addrman = TestAddrMan();
99+
addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
97100
std::vector<CAddress> vAddr;
98101
vAddr.push_back(CAddress(ResolveService("250.1.1.3", 8333), NODE_NONE));
99102
vAddr.push_back(CAddress(ResolveService("250.1.1.4", 8333), NODE_NONE));
@@ -103,7 +106,7 @@ BOOST_AUTO_TEST_CASE(addrman_simple)
103106

104107
BOOST_AUTO_TEST_CASE(addrman_ports)
105108
{
106-
auto addrman = TestAddrMan();
109+
auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
107110

108111
CNetAddr source = ResolveIP("252.2.2.2");
109112

@@ -132,7 +135,7 @@ BOOST_AUTO_TEST_CASE(addrman_ports)
132135

133136
BOOST_AUTO_TEST_CASE(addrman_select)
134137
{
135-
auto addrman = TestAddrMan();
138+
auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
136139

137140
CNetAddr source = ResolveIP("252.2.2.2");
138141

@@ -191,7 +194,7 @@ BOOST_AUTO_TEST_CASE(addrman_select)
191194

192195
BOOST_AUTO_TEST_CASE(addrman_new_collisions)
193196
{
194-
auto addrman = TestAddrMan();
197+
auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
195198

196199
CNetAddr source = ResolveIP("252.2.2.2");
197200

@@ -220,7 +223,7 @@ BOOST_AUTO_TEST_CASE(addrman_new_collisions)
220223

221224
BOOST_AUTO_TEST_CASE(addrman_new_multiplicity)
222225
{
223-
auto addrman = TestAddrMan();
226+
auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
224227
CAddress addr{CAddress(ResolveService("253.3.3.3", 8333), NODE_NONE)};
225228
int64_t start_time{GetAdjustedTime()};
226229
addr.nTime = start_time;
@@ -252,7 +255,7 @@ BOOST_AUTO_TEST_CASE(addrman_new_multiplicity)
252255

253256
BOOST_AUTO_TEST_CASE(addrman_tried_collisions)
254257
{
255-
auto addrman = TestAddrMan();
258+
auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
256259

257260
CNetAddr source = ResolveIP("252.2.2.2");
258261

@@ -283,7 +286,7 @@ BOOST_AUTO_TEST_CASE(addrman_tried_collisions)
283286

284287
BOOST_AUTO_TEST_CASE(addrman_getaddr)
285288
{
286-
auto addrman = TestAddrMan();
289+
auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
287290

288291
// Test: Sanity check, GetAddr should never return anything if addrman
289292
// is empty.
@@ -604,9 +607,11 @@ BOOST_AUTO_TEST_CASE(addrman_serialization)
604607
{
605608
std::vector<bool> asmap1 = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
606609

607-
auto addrman_asmap1 = TestAddrMan(asmap1);
608-
auto addrman_asmap1_dup = TestAddrMan(asmap1);
609-
auto addrman_noasmap = TestAddrMan();
610+
const auto ratio = GetCheckRatio(m_node);
611+
auto addrman_asmap1 = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio);
612+
auto addrman_asmap1_dup = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio);
613+
auto addrman_noasmap = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, ratio);
614+
610615
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
611616

612617
CAddress addr = CAddress(ResolveService("250.1.1.1"), NODE_NONE);
@@ -634,8 +639,8 @@ BOOST_AUTO_TEST_CASE(addrman_serialization)
634639
BOOST_CHECK(addr_pos1.position != addr_pos3.position);
635640

636641
// deserializing non-asmaped peers.dat to asmaped addrman
637-
addrman_asmap1 = TestAddrMan(asmap1);
638-
addrman_noasmap = TestAddrMan();
642+
addrman_asmap1 = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio);
643+
addrman_noasmap = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, ratio);
639644
addrman_noasmap->Add({addr}, default_source);
640645
stream << *addrman_noasmap;
641646
stream >> *addrman_asmap1;
@@ -646,8 +651,8 @@ BOOST_AUTO_TEST_CASE(addrman_serialization)
646651
BOOST_CHECK(addr_pos4 == addr_pos2);
647652

648653
// used to map to different buckets, now maps to the same bucket.
649-
addrman_asmap1 = TestAddrMan(asmap1);
650-
addrman_noasmap = TestAddrMan();
654+
addrman_asmap1 = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio);
655+
addrman_noasmap = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, ratio);
651656
CAddress addr1 = CAddress(ResolveService("250.1.1.1"), NODE_NONE);
652657
CAddress addr2 = CAddress(ResolveService("250.2.1.1"), NODE_NONE);
653658
addrman_noasmap->Add({addr, addr2}, default_source);
@@ -666,7 +671,7 @@ BOOST_AUTO_TEST_CASE(remove_invalid)
666671
{
667672
// Confirm that invalid addresses are ignored in unserialization.
668673

669-
auto addrman = TestAddrMan();
674+
auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
670675
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
671676

672677
const CAddress new1{ResolveService("5.5.5.5"), NODE_NONE};
@@ -698,14 +703,14 @@ BOOST_AUTO_TEST_CASE(remove_invalid)
698703
BOOST_REQUIRE(pos + sizeof(tried2_raw_replacement) <= stream.size());
699704
memcpy(stream.data() + pos, tried2_raw_replacement, sizeof(tried2_raw_replacement));
700705

701-
addrman = TestAddrMan();
706+
addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
702707
stream >> *addrman;
703708
BOOST_CHECK_EQUAL(addrman->size(), 2);
704709
}
705710

706711
BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
707712
{
708-
auto addrman = TestAddrMan();
713+
auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
709714

710715
BOOST_CHECK(addrman->size() == 0);
711716

@@ -738,7 +743,7 @@ BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
738743

739744
BOOST_AUTO_TEST_CASE(addrman_noevict)
740745
{
741-
auto addrman = TestAddrMan();
746+
auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
742747

743748
// Add 35 addresses.
744749
CNetAddr source = ResolveIP("252.2.2.2");
@@ -790,7 +795,7 @@ BOOST_AUTO_TEST_CASE(addrman_noevict)
790795

791796
BOOST_AUTO_TEST_CASE(addrman_evictionworks)
792797
{
793-
auto addrman = TestAddrMan();
798+
auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
794799

795800
BOOST_CHECK(addrman->size() == 0);
796801

@@ -860,8 +865,7 @@ static CDataStream AddrmanToStream(const AddrMan& addrman)
860865

861866
BOOST_AUTO_TEST_CASE(load_addrman)
862867
{
863-
AddrMan addrman{/*asmap=*/ std::vector<bool>(), /*deterministic=*/ true,
864-
/*consistency_check_ratio=*/ 100};
868+
AddrMan addrman{EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node)};
865869

866870
CService addr1, addr2, addr3;
867871
BOOST_CHECK(Lookup("250.7.1.1", addr1, 8333, false));
@@ -880,7 +884,7 @@ BOOST_AUTO_TEST_CASE(load_addrman)
880884
// Test that the de-serialization does not throw an exception.
881885
CDataStream ssPeers1 = AddrmanToStream(addrman);
882886
bool exceptionThrown = false;
883-
AddrMan addrman1(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/100);
887+
AddrMan addrman1{EMPTY_ASMAP, !DETERMINISTIC, GetCheckRatio(m_node)};
884888

885889
BOOST_CHECK(addrman1.size() == 0);
886890
try {
@@ -897,7 +901,7 @@ BOOST_AUTO_TEST_CASE(load_addrman)
897901
// Test that ReadFromStream creates an addrman with the correct number of addrs.
898902
CDataStream ssPeers2 = AddrmanToStream(addrman);
899903

900-
AddrMan addrman2(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/100);
904+
AddrMan addrman2{EMPTY_ASMAP, !DETERMINISTIC, GetCheckRatio(m_node)};
901905
BOOST_CHECK(addrman2.size() == 0);
902906
ReadFromStream(addrman2, ssPeers2);
903907
BOOST_CHECK(addrman2.size() == 3);
@@ -935,7 +939,7 @@ BOOST_AUTO_TEST_CASE(load_addrman_corrupted)
935939
// Test that the de-serialization of corrupted peers.dat throws an exception.
936940
CDataStream ssPeers1 = MakeCorruptPeersDat();
937941
bool exceptionThrown = false;
938-
AddrMan addrman1(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/100);
942+
AddrMan addrman1{EMPTY_ASMAP, !DETERMINISTIC, GetCheckRatio(m_node)};
939943
BOOST_CHECK(addrman1.size() == 0);
940944
try {
941945
unsigned char pchMsgTmp[4];
@@ -951,15 +955,15 @@ BOOST_AUTO_TEST_CASE(load_addrman_corrupted)
951955
// Test that ReadFromStream fails if peers.dat is corrupt
952956
CDataStream ssPeers2 = MakeCorruptPeersDat();
953957

954-
AddrMan addrman2(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/100);
958+
AddrMan addrman2{EMPTY_ASMAP, !DETERMINISTIC, GetCheckRatio(m_node)};
955959
BOOST_CHECK(addrman2.size() == 0);
956960
BOOST_CHECK_THROW(ReadFromStream(addrman2, ssPeers2), std::ios_base::failure);
957961
}
958962

959963
BOOST_AUTO_TEST_CASE(addrman_update_address)
960964
{
961965
// Tests updating nTime via Connected() and nServices via SetServices()
962-
auto addrman = TestAddrMan();
966+
auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
963967
CNetAddr source{ResolveIP("252.2.2.2")};
964968
CAddress addr{CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE)};
965969

0 commit comments

Comments
 (0)