0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-03 09:56:38 -05:00

Merge bitcoin/bitcoin#23373: test: Parse command line arguments from unit and fuzz tests, make addrman consistency check ratio easier to change

7f122a4188 fuzz: non-addrman fuzz tests: override-able check ratio (Vasil Dimov)
3bd83e273d fuzz: addrman fuzz tests: override-able check ratio (Vasil Dimov)
46b0fe7829 test: non-addrman unit tests: override-able check ratio (Vasil Dimov)
81e4d54d3a test: addrman unit tests: override-able check ratio (Vasil Dimov)
6dff6214be bench: put addrman check ratio in a variable (Vasil Dimov)
6f7c7567c5 fuzz: parse the command line arguments in fuzz tests (Vasil Dimov)
92a0f7e58d 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 https://github.com/bitcoin/bitcoin/pull/20233#issuecomment-889813074 for further motivation for this.

ACKs for top commit:
  mzumsande:
    re-ACK 7f122a4188
  josibake:
    reACK 7f122a4188

Tree-SHA512: 3a05e61e4d70a0569bb67594bcce3aad8fdef63cdcc54e2823a3bc9f18679571985004412b6c332a210f67849bab32d8467b4115fbff8f5fac9834982e60dcf3
This commit is contained in:
MarcoFalke 2022-01-17 09:10:10 +01:00
commit d0bf9bb6a5
No known key found for this signature in database
GPG key ID: CE2B75697E69A548
13 changed files with 170 additions and 55 deletions

View file

@ -71,6 +71,15 @@ block^@M-^?M-^?M-^?M-^?M-^?nM-^?M-^?
In this case the fuzzer managed to create a `block` message which when passed to `ProcessMessage(...)` increased coverage. In this case the fuzzer managed to create a `block` message which when passed to `ProcessMessage(...)` increased coverage.
It is possible to specify `bitcoind` arguments to the `fuzz` executable.
Depending on the test, they may be ignored or consumed and alter the behavior
of the test. Just make sure to use double-dash to distinguish them from the
fuzzer's own arguments:
```sh
$ FUZZ=address_deserialize_v2 src/test/fuzz/fuzz -runs=1 fuzz_seed_corpus/address_deserialize_v2 --checkaddrman=5 --printtoconsole=1
```
## Fuzzing corpora ## Fuzzing corpora
The project's collection of seed corpora is found in the [`bitcoin-core/qa-assets`](https://github.com/bitcoin-core/qa-assets) repo. The project's collection of seed corpora is found in the [`bitcoin-core/qa-assets`](https://github.com/bitcoin-core/qa-assets) repo.

View file

@ -16,6 +16,9 @@
static constexpr size_t NUM_SOURCES = 64; static constexpr size_t NUM_SOURCES = 64;
static constexpr size_t NUM_ADDRESSES_PER_SOURCE = 256; static constexpr size_t NUM_ADDRESSES_PER_SOURCE = 256;
static const std::vector<bool> EMPTY_ASMAP;
static constexpr uint32_t ADDRMAN_CONSISTENCY_CHECK_RATIO{0};
static std::vector<CAddress> g_sources; static std::vector<CAddress> g_sources;
static std::vector<std::vector<CAddress>> g_addresses; static std::vector<std::vector<CAddress>> g_addresses;
@ -74,14 +77,14 @@ static void AddrManAdd(benchmark::Bench& bench)
CreateAddresses(); CreateAddresses();
bench.run([&] { bench.run([&] {
AddrMan addrman{/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0}; AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
AddAddressesToAddrMan(addrman); AddAddressesToAddrMan(addrman);
}); });
} }
static void AddrManSelect(benchmark::Bench& bench) static void AddrManSelect(benchmark::Bench& bench)
{ {
AddrMan addrman(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0); AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
FillAddrMan(addrman); FillAddrMan(addrman);
@ -93,7 +96,7 @@ static void AddrManSelect(benchmark::Bench& bench)
static void AddrManGetAddr(benchmark::Bench& bench) static void AddrManGetAddr(benchmark::Bench& bench)
{ {
AddrMan addrman(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0); AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
FillAddrMan(addrman); FillAddrMan(addrman);
@ -122,7 +125,7 @@ static void AddrManAddThenGood(benchmark::Bench& bench)
// //
// This has some overhead (exactly the result of AddrManAdd benchmark), but that overhead is constant so improvements in // This has some overhead (exactly the result of AddrManAdd benchmark), but that overhead is constant so improvements in
// AddrMan::Good() will still be noticeable. // AddrMan::Good() will still be noticeable.
AddrMan addrman(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0); AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
AddAddressesToAddrMan(addrman); AddAddressesToAddrMan(addrman);
markSomeAsGood(addrman); markSomeAsGood(addrman);

View file

@ -19,6 +19,8 @@ using namespace std::chrono_literals;
const std::function<void(const std::string&)> G_TEST_LOG_FUN{}; const std::function<void(const std::string&)> G_TEST_LOG_FUN{};
const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUMENTS{};
namespace { namespace {
void GenerateTemplateResults(const std::vector<ankerl::nanobench::Result>& benchmarkResults, const std::string& filename, const char* tpl) void GenerateTemplateResults(const std::vector<ankerl::nanobench::Result>& benchmarkResults, const std::string& filename, const char* tpl)

View file

@ -22,6 +22,7 @@
#include <QApplication> #include <QApplication>
#include <QObject> #include <QObject>
#include <QTest> #include <QTest>
#include <functional>
#if defined(QT_STATICPLUGIN) #if defined(QT_STATICPLUGIN)
#include <QtPlugin> #include <QtPlugin>
@ -43,6 +44,8 @@ using node::NodeContext;
const std::function<void(const std::string&)> G_TEST_LOG_FUN{}; const std::function<void(const std::string&)> G_TEST_LOG_FUN{};
const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUMENTS{};
// This is all you need to run all the tests // This is all you need to run all the tests
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {

View file

@ -33,19 +33,31 @@ the `src/qt/test/test_main.cpp` file.
### Running individual tests ### Running individual tests
`test_bitcoin` has some built-in command-line arguments; for `test_bitcoin` accepts the command line arguments from the boost framework.
example, to run just the `getarg_tests` verbosely: For example, to run just the `getarg_tests` suite of tests:
test_bitcoin --log_level=all --run_test=getarg_tests -- DEBUG_LOG_OUT ```bash
test_bitcoin --log_level=all --run_test=getarg_tests
```
`log_level` controls the verbosity of the test framework, which logs when a `log_level` controls the verbosity of the test framework, which logs when a
test case is entered, for example. The `DEBUG_LOG_OUT` after the two dashes test case is entered, for example. `test_bitcoin` also accepts the command
redirects the debug log, which would normally go to a file in the test datadir line arguments accepted by `bitcoind`. Use `--` to separate both types of
arguments:
```bash
test_bitcoin --log_level=all --run_test=getarg_tests -- -printtoconsole=1
```
The `-printtoconsole=1` after the two dashes redirects the debug log, which
would normally go to a file in the test datadir
(`BasicTestingSetup::m_path_root`), to the standard terminal output. (`BasicTestingSetup::m_path_root`), to the standard terminal output.
... or to run just the doubledash test: ... or to run just the doubledash test:
test_bitcoin --run_test=getarg_tests/doubledash ```bash
test_bitcoin --run_test=getarg_tests/doubledash
```
Run `test_bitcoin --help` for the full list. Run `test_bitcoin --help` for the full list.
@ -68,7 +80,7 @@ on failure. For running individual tests verbosely, refer to the section
To write to logs from unit tests you need to use specific message methods To write to logs from unit tests you need to use specific message methods
provided by Boost. The simplest is `BOOST_TEST_MESSAGE`. provided by Boost. The simplest is `BOOST_TEST_MESSAGE`.
For debugging you can launch the `test_bitcoin` executable with `gdb`or `lldb` and For debugging you can launch the `test_bitcoin` executable with `gdb` or `lldb` and
start debugging, just like you would with any other program: start debugging, just like you would with any other program:
```bash ```bash
@ -95,7 +107,7 @@ Running the tests and hitting a segmentation fault should now produce a file cal
`/proc/sys/kernel/core_pattern`). `/proc/sys/kernel/core_pattern`).
You can then explore the core dump using You can then explore the core dump using
``` bash ```bash
gdb src/test/test_bitcoin core gdb src/test/test_bitcoin core
(gbd) bt # produce a backtrace for where a segfault occurred (gbd) bt # produce a backtrace for where a segfault occurred

View file

@ -21,6 +21,15 @@
#include <string> #include <string>
using namespace std::literals; using namespace std::literals;
using node::NodeContext;
static const std::vector<bool> EMPTY_ASMAP;
static const bool DETERMINISTIC{true};
static int32_t GetCheckRatio(const NodeContext& node_ctx)
{
return std::clamp<int32_t>(node_ctx.args->GetIntArg("-checkaddrman", 100), 0, 1000000);
}
static CNetAddr ResolveIP(const std::string& ip) static CNetAddr ResolveIP(const std::string& ip)
{ {
@ -49,17 +58,11 @@ static std::vector<bool> FromBytes(const unsigned char* source, int vector_size)
return result; return result;
} }
/* Utility function to create a deterministic addrman, as used in most tests */
static std::unique_ptr<AddrMan> TestAddrMan(std::vector<bool> asmap = std::vector<bool>())
{
return std::make_unique<AddrMan>(asmap, /*deterministic=*/true, /*consistency_check_ratio=*/100);
}
BOOST_FIXTURE_TEST_SUITE(addrman_tests, BasicTestingSetup) BOOST_FIXTURE_TEST_SUITE(addrman_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(addrman_simple) BOOST_AUTO_TEST_CASE(addrman_simple)
{ {
auto addrman = TestAddrMan(); auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source = ResolveIP("252.2.2.2"); CNetAddr source = ResolveIP("252.2.2.2");
@ -93,7 +96,7 @@ BOOST_AUTO_TEST_CASE(addrman_simple)
BOOST_CHECK(addrman->size() >= 1); BOOST_CHECK(addrman->size() >= 1);
// Test: reset addrman and test AddrMan::Add multiple addresses works as expected // Test: reset addrman and test AddrMan::Add multiple addresses works as expected
addrman = TestAddrMan(); addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
std::vector<CAddress> vAddr; std::vector<CAddress> vAddr;
vAddr.push_back(CAddress(ResolveService("250.1.1.3", 8333), NODE_NONE)); vAddr.push_back(CAddress(ResolveService("250.1.1.3", 8333), NODE_NONE));
vAddr.push_back(CAddress(ResolveService("250.1.1.4", 8333), NODE_NONE)); vAddr.push_back(CAddress(ResolveService("250.1.1.4", 8333), NODE_NONE));
@ -103,7 +106,7 @@ BOOST_AUTO_TEST_CASE(addrman_simple)
BOOST_AUTO_TEST_CASE(addrman_ports) BOOST_AUTO_TEST_CASE(addrman_ports)
{ {
auto addrman = TestAddrMan(); auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source = ResolveIP("252.2.2.2"); CNetAddr source = ResolveIP("252.2.2.2");
@ -132,7 +135,7 @@ BOOST_AUTO_TEST_CASE(addrman_ports)
BOOST_AUTO_TEST_CASE(addrman_select) BOOST_AUTO_TEST_CASE(addrman_select)
{ {
auto addrman = TestAddrMan(); auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source = ResolveIP("252.2.2.2"); CNetAddr source = ResolveIP("252.2.2.2");
@ -191,7 +194,7 @@ BOOST_AUTO_TEST_CASE(addrman_select)
BOOST_AUTO_TEST_CASE(addrman_new_collisions) BOOST_AUTO_TEST_CASE(addrman_new_collisions)
{ {
auto addrman = TestAddrMan(); auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source = ResolveIP("252.2.2.2"); CNetAddr source = ResolveIP("252.2.2.2");
@ -220,7 +223,7 @@ BOOST_AUTO_TEST_CASE(addrman_new_collisions)
BOOST_AUTO_TEST_CASE(addrman_new_multiplicity) BOOST_AUTO_TEST_CASE(addrman_new_multiplicity)
{ {
auto addrman = TestAddrMan(); auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
CAddress addr{CAddress(ResolveService("253.3.3.3", 8333), NODE_NONE)}; CAddress addr{CAddress(ResolveService("253.3.3.3", 8333), NODE_NONE)};
int64_t start_time{GetAdjustedTime()}; int64_t start_time{GetAdjustedTime()};
addr.nTime = start_time; addr.nTime = start_time;
@ -252,7 +255,7 @@ BOOST_AUTO_TEST_CASE(addrman_new_multiplicity)
BOOST_AUTO_TEST_CASE(addrman_tried_collisions) BOOST_AUTO_TEST_CASE(addrman_tried_collisions)
{ {
auto addrman = TestAddrMan(); auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source = ResolveIP("252.2.2.2"); CNetAddr source = ResolveIP("252.2.2.2");
@ -283,7 +286,7 @@ BOOST_AUTO_TEST_CASE(addrman_tried_collisions)
BOOST_AUTO_TEST_CASE(addrman_getaddr) BOOST_AUTO_TEST_CASE(addrman_getaddr)
{ {
auto addrman = TestAddrMan(); auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
// Test: Sanity check, GetAddr should never return anything if addrman // Test: Sanity check, GetAddr should never return anything if addrman
// is empty. // is empty.
@ -604,9 +607,11 @@ BOOST_AUTO_TEST_CASE(addrman_serialization)
{ {
std::vector<bool> asmap1 = FromBytes(asmap_raw, sizeof(asmap_raw) * 8); std::vector<bool> asmap1 = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
auto addrman_asmap1 = TestAddrMan(asmap1); const auto ratio = GetCheckRatio(m_node);
auto addrman_asmap1_dup = TestAddrMan(asmap1); auto addrman_asmap1 = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio);
auto addrman_noasmap = TestAddrMan(); auto addrman_asmap1_dup = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio);
auto addrman_noasmap = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, ratio);
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
CAddress addr = CAddress(ResolveService("250.1.1.1"), NODE_NONE); CAddress addr = CAddress(ResolveService("250.1.1.1"), NODE_NONE);
@ -634,8 +639,8 @@ BOOST_AUTO_TEST_CASE(addrman_serialization)
BOOST_CHECK(addr_pos1.position != addr_pos3.position); BOOST_CHECK(addr_pos1.position != addr_pos3.position);
// deserializing non-asmaped peers.dat to asmaped addrman // deserializing non-asmaped peers.dat to asmaped addrman
addrman_asmap1 = TestAddrMan(asmap1); addrman_asmap1 = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio);
addrman_noasmap = TestAddrMan(); addrman_noasmap = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, ratio);
addrman_noasmap->Add({addr}, default_source); addrman_noasmap->Add({addr}, default_source);
stream << *addrman_noasmap; stream << *addrman_noasmap;
stream >> *addrman_asmap1; stream >> *addrman_asmap1;
@ -646,8 +651,8 @@ BOOST_AUTO_TEST_CASE(addrman_serialization)
BOOST_CHECK(addr_pos4 == addr_pos2); BOOST_CHECK(addr_pos4 == addr_pos2);
// used to map to different buckets, now maps to the same bucket. // used to map to different buckets, now maps to the same bucket.
addrman_asmap1 = TestAddrMan(asmap1); addrman_asmap1 = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio);
addrman_noasmap = TestAddrMan(); addrman_noasmap = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, ratio);
CAddress addr1 = CAddress(ResolveService("250.1.1.1"), NODE_NONE); CAddress addr1 = CAddress(ResolveService("250.1.1.1"), NODE_NONE);
CAddress addr2 = CAddress(ResolveService("250.2.1.1"), NODE_NONE); CAddress addr2 = CAddress(ResolveService("250.2.1.1"), NODE_NONE);
addrman_noasmap->Add({addr, addr2}, default_source); addrman_noasmap->Add({addr, addr2}, default_source);
@ -666,7 +671,7 @@ BOOST_AUTO_TEST_CASE(remove_invalid)
{ {
// Confirm that invalid addresses are ignored in unserialization. // Confirm that invalid addresses are ignored in unserialization.
auto addrman = TestAddrMan(); auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
const CAddress new1{ResolveService("5.5.5.5"), NODE_NONE}; const CAddress new1{ResolveService("5.5.5.5"), NODE_NONE};
@ -698,14 +703,14 @@ BOOST_AUTO_TEST_CASE(remove_invalid)
BOOST_REQUIRE(pos + sizeof(tried2_raw_replacement) <= stream.size()); BOOST_REQUIRE(pos + sizeof(tried2_raw_replacement) <= stream.size());
memcpy(stream.data() + pos, tried2_raw_replacement, sizeof(tried2_raw_replacement)); memcpy(stream.data() + pos, tried2_raw_replacement, sizeof(tried2_raw_replacement));
addrman = TestAddrMan(); addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
stream >> *addrman; stream >> *addrman;
BOOST_CHECK_EQUAL(addrman->size(), 2); BOOST_CHECK_EQUAL(addrman->size(), 2);
} }
BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision) BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
{ {
auto addrman = TestAddrMan(); auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
BOOST_CHECK(addrman->size() == 0); BOOST_CHECK(addrman->size() == 0);
@ -738,7 +743,7 @@ BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
BOOST_AUTO_TEST_CASE(addrman_noevict) BOOST_AUTO_TEST_CASE(addrman_noevict)
{ {
auto addrman = TestAddrMan(); auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
// Add 35 addresses. // Add 35 addresses.
CNetAddr source = ResolveIP("252.2.2.2"); CNetAddr source = ResolveIP("252.2.2.2");
@ -790,7 +795,7 @@ BOOST_AUTO_TEST_CASE(addrman_noevict)
BOOST_AUTO_TEST_CASE(addrman_evictionworks) BOOST_AUTO_TEST_CASE(addrman_evictionworks)
{ {
auto addrman = TestAddrMan(); auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
BOOST_CHECK(addrman->size() == 0); BOOST_CHECK(addrman->size() == 0);
@ -860,8 +865,7 @@ static CDataStream AddrmanToStream(const AddrMan& addrman)
BOOST_AUTO_TEST_CASE(load_addrman) BOOST_AUTO_TEST_CASE(load_addrman)
{ {
AddrMan addrman{/*asmap=*/ std::vector<bool>(), /*deterministic=*/ true, AddrMan addrman{EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node)};
/*consistency_check_ratio=*/ 100};
CService addr1, addr2, addr3; CService addr1, addr2, addr3;
BOOST_CHECK(Lookup("250.7.1.1", addr1, 8333, false)); BOOST_CHECK(Lookup("250.7.1.1", addr1, 8333, false));
@ -880,7 +884,7 @@ BOOST_AUTO_TEST_CASE(load_addrman)
// Test that the de-serialization does not throw an exception. // Test that the de-serialization does not throw an exception.
CDataStream ssPeers1 = AddrmanToStream(addrman); CDataStream ssPeers1 = AddrmanToStream(addrman);
bool exceptionThrown = false; bool exceptionThrown = false;
AddrMan addrman1(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/100); AddrMan addrman1{EMPTY_ASMAP, !DETERMINISTIC, GetCheckRatio(m_node)};
BOOST_CHECK(addrman1.size() == 0); BOOST_CHECK(addrman1.size() == 0);
try { try {
@ -897,7 +901,7 @@ BOOST_AUTO_TEST_CASE(load_addrman)
// Test that ReadFromStream creates an addrman with the correct number of addrs. // Test that ReadFromStream creates an addrman with the correct number of addrs.
CDataStream ssPeers2 = AddrmanToStream(addrman); CDataStream ssPeers2 = AddrmanToStream(addrman);
AddrMan addrman2(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/100); AddrMan addrman2{EMPTY_ASMAP, !DETERMINISTIC, GetCheckRatio(m_node)};
BOOST_CHECK(addrman2.size() == 0); BOOST_CHECK(addrman2.size() == 0);
ReadFromStream(addrman2, ssPeers2); ReadFromStream(addrman2, ssPeers2);
BOOST_CHECK(addrman2.size() == 3); BOOST_CHECK(addrman2.size() == 3);
@ -935,7 +939,7 @@ BOOST_AUTO_TEST_CASE(load_addrman_corrupted)
// Test that the de-serialization of corrupted peers.dat throws an exception. // Test that the de-serialization of corrupted peers.dat throws an exception.
CDataStream ssPeers1 = MakeCorruptPeersDat(); CDataStream ssPeers1 = MakeCorruptPeersDat();
bool exceptionThrown = false; bool exceptionThrown = false;
AddrMan addrman1(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/100); AddrMan addrman1{EMPTY_ASMAP, !DETERMINISTIC, GetCheckRatio(m_node)};
BOOST_CHECK(addrman1.size() == 0); BOOST_CHECK(addrman1.size() == 0);
try { try {
unsigned char pchMsgTmp[4]; unsigned char pchMsgTmp[4];
@ -951,7 +955,7 @@ BOOST_AUTO_TEST_CASE(load_addrman_corrupted)
// Test that ReadFromStream fails if peers.dat is corrupt // Test that ReadFromStream fails if peers.dat is corrupt
CDataStream ssPeers2 = MakeCorruptPeersDat(); CDataStream ssPeers2 = MakeCorruptPeersDat();
AddrMan addrman2(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/100); AddrMan addrman2{EMPTY_ASMAP, !DETERMINISTIC, GetCheckRatio(m_node)};
BOOST_CHECK(addrman2.size() == 0); BOOST_CHECK(addrman2.size() == 0);
BOOST_CHECK_THROW(ReadFromStream(addrman2, ssPeers2), std::ios_base::failure); BOOST_CHECK_THROW(ReadFromStream(addrman2, ssPeers2), std::ios_base::failure);
} }
@ -959,7 +963,7 @@ BOOST_AUTO_TEST_CASE(load_addrman_corrupted)
BOOST_AUTO_TEST_CASE(addrman_update_address) BOOST_AUTO_TEST_CASE(addrman_update_address)
{ {
// Tests updating nTime via Connected() and nServices via SetServices() // Tests updating nTime via Connected() and nServices via SetServices()
auto addrman = TestAddrMan(); auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source{ResolveIP("252.2.2.2")}; CNetAddr source{ResolveIP("252.2.2.2")};
CAddress addr{CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE)}; CAddress addr{CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE)};

View file

@ -11,8 +11,10 @@
#include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h> #include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h> #include <test/fuzz/util.h>
#include <test/util/setup_common.h>
#include <time.h> #include <time.h>
#include <util/asmap.h> #include <util/asmap.h>
#include <util/system.h>
#include <cassert> #include <cassert>
#include <cstdint> #include <cstdint>
@ -20,16 +22,26 @@
#include <string> #include <string>
#include <vector> #include <vector>
namespace {
const BasicTestingSetup* g_setup;
int32_t GetCheckRatio()
{
return std::clamp<int32_t>(g_setup->m_node.args->GetIntArg("-checkaddrman", 0), 0, 1000000);
}
} // namespace
void initialize_addrman() void initialize_addrman()
{ {
SelectParams(CBaseChainParams::REGTEST); static const auto testing_setup = MakeNoLogFileContext<>(CBaseChainParams::REGTEST);
g_setup = testing_setup.get();
} }
FUZZ_TARGET_INIT(data_stream_addr_man, initialize_addrman) FUZZ_TARGET_INIT(data_stream_addr_man, initialize_addrman)
{ {
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
CDataStream data_stream = ConsumeDataStream(fuzzed_data_provider); CDataStream data_stream = ConsumeDataStream(fuzzed_data_provider);
AddrMan addr_man(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/0); AddrMan addr_man{/*asmap=*/std::vector<bool>(), /*deterministic=*/false, GetCheckRatio()};
try { try {
ReadFromStream(addr_man, data_stream); ReadFromStream(addr_man, data_stream);
} catch (const std::exception&) { } catch (const std::exception&) {
@ -113,7 +125,7 @@ class AddrManDeterministic : public AddrMan
{ {
public: public:
explicit AddrManDeterministic(std::vector<bool> asmap, FuzzedDataProvider& fuzzed_data_provider) explicit AddrManDeterministic(std::vector<bool> asmap, FuzzedDataProvider& fuzzed_data_provider)
: AddrMan(std::move(asmap), /*deterministic=*/true, /*consistency_check_ratio=*/0) : AddrMan{std::move(asmap), /*deterministic=*/true, GetCheckRatio()}
{ {
WITH_LOCK(m_impl->cs, m_impl->insecure_rand = FastRandomContext{ConsumeUInt256(fuzzed_data_provider)}); WITH_LOCK(m_impl->cs, m_impl->insecure_rand = FastRandomContext{ConsumeUInt256(fuzzed_data_provider)});
} }

View file

@ -12,21 +12,29 @@
#include <test/fuzz/fuzz.h> #include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h> #include <test/fuzz/util.h>
#include <test/util/setup_common.h> #include <test/util/setup_common.h>
#include <util/system.h>
#include <util/translation.h> #include <util/translation.h>
#include <cstdint> #include <cstdint>
#include <vector> #include <vector>
namespace {
const BasicTestingSetup* g_setup;
} // namespace
void initialize_connman() void initialize_connman()
{ {
static const auto testing_setup = MakeNoLogFileContext<>(); static const auto testing_setup = MakeNoLogFileContext<>();
g_setup = testing_setup.get();
} }
FUZZ_TARGET_INIT(connman, initialize_connman) FUZZ_TARGET_INIT(connman, initialize_connman)
{ {
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
SetMockTime(ConsumeTime(fuzzed_data_provider)); SetMockTime(ConsumeTime(fuzzed_data_provider));
AddrMan addrman(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/0); AddrMan addrman(/*asmap=*/std::vector<bool>(),
/*deterministic=*/false,
g_setup->m_node.args->GetIntArg("-checkaddrman", 0));
CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>(), addrman, fuzzed_data_provider.ConsumeBool()}; CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>(), addrman, fuzzed_data_provider.ConsumeBool()};
CNetAddr random_netaddr; CNetAddr random_netaddr;
CNode random_node = ConsumeNode(fuzzed_data_provider); CNode random_node = ConsumeNode(fuzzed_data_provider);

View file

@ -22,7 +22,9 @@
#include <pubkey.h> #include <pubkey.h>
#include <script/keyorigin.h> #include <script/keyorigin.h>
#include <streams.h> #include <streams.h>
#include <test/util/setup_common.h>
#include <undo.h> #include <undo.h>
#include <util/system.h>
#include <version.h> #include <version.h>
#include <exception> #include <exception>
@ -35,8 +37,15 @@
using node::SnapshotMetadata; using node::SnapshotMetadata;
namespace {
const BasicTestingSetup* g_setup;
} // namespace
void initialize_deserialize() void initialize_deserialize()
{ {
static const auto testing_setup = MakeNoLogFileContext<>();
g_setup = testing_setup.get();
// Fuzzers using pubkey must hold an ECCVerifyHandle. // Fuzzers using pubkey must hold an ECCVerifyHandle.
static const ECCVerifyHandle verify_handle; static const ECCVerifyHandle verify_handle;
} }
@ -191,7 +200,9 @@ FUZZ_TARGET_DESERIALIZE(blockmerkleroot, {
BlockMerkleRoot(block, &mutated); BlockMerkleRoot(block, &mutated);
}) })
FUZZ_TARGET_DESERIALIZE(addrman_deserialize, { FUZZ_TARGET_DESERIALIZE(addrman_deserialize, {
AddrMan am(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/0); AddrMan am(/*asmap=*/std::vector<bool>(),
/*deterministic=*/false,
g_setup->m_node.args->GetIntArg("-checkaddrman", 0));
DeserializeFromFuzzingInput(buffer, am); DeserializeFromFuzzingInput(buffer, am);
}) })
FUZZ_TARGET_DESERIALIZE(blockheader_deserialize, { FUZZ_TARGET_DESERIALIZE(blockheader_deserialize, {

View file

@ -12,6 +12,7 @@
#include <cstdint> #include <cstdint>
#include <exception> #include <exception>
#include <functional>
#include <memory> #include <memory>
#include <string> #include <string>
#include <unistd.h> #include <unistd.h>
@ -19,6 +20,29 @@
const std::function<void(const std::string&)> G_TEST_LOG_FUN{}; const std::function<void(const std::string&)> G_TEST_LOG_FUN{};
/**
* A copy of the command line arguments that start with `--`.
* First `LLVMFuzzerInitialize()` is called, which saves the arguments to `g_args`.
* Later, depending on the fuzz test, `G_TEST_COMMAND_LINE_ARGUMENTS()` may be
* called by `BasicTestingSetup` constructor to fetch those arguments and store
* them in `BasicTestingSetup::m_node::args`.
*/
static std::vector<const char*> g_args;
static void SetArgs(int argc, char** argv) {
for (int i = 1; i < argc; ++i) {
// Only take into account arguments that start with `--`. The others are for the fuzz engine:
// `fuzz -runs=1 fuzz_seed_corpus/address_deserialize_v2 --checkaddrman=5`
if (strlen(argv[i]) > 2 && argv[i][0] == '-' && argv[i][1] == '-') {
g_args.push_back(argv[i]);
}
}
}
const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUMENTS = []() {
return g_args;
};
std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize, TypeHidden>>& FuzzTargets() std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize, TypeHidden>>& FuzzTargets()
{ {
static std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize, TypeHidden>> g_fuzz_targets; static std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize, TypeHidden>> g_fuzz_targets;
@ -95,6 +119,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
// This function is used by libFuzzer // This function is used by libFuzzer
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
{ {
SetArgs(*argc, *argv);
initialize(); initialize();
return 0; return 0;
} }

View file

@ -11,6 +11,7 @@
#include <test/util/setup_common.h> #include <test/util/setup_common.h>
#include <functional>
#include <iostream> #include <iostream>
/** Redirect debug log to unit_test.log files */ /** Redirect debug log to unit_test.log files */
@ -24,3 +25,17 @@ const std::function<void(const std::string&)> G_TEST_LOG_FUN = [](const std::str
if (!should_log) return; if (!should_log) return;
std::cout << s; std::cout << s;
}; };
/**
* Retrieve the command line arguments from boost.
* Allows usage like:
* `test_bitcoin --run_test="net_tests/cnode_listen_port" -- -checkaddrman=1 -printtoconsole=1`
* which would return `["-checkaddrman=1", "-printtoconsole=1"]`.
*/
const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUMENTS = []() {
std::vector<const char*> args;
for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) {
args.push_back(boost::unit_test::framework::master_test_suite().argv[i]);
}
return args;
};

View file

@ -42,6 +42,7 @@
#include <walletinitinterface.h> #include <walletinitinterface.h>
#include <functional> #include <functional>
#include <stdexcept>
using node::BlockAssembler; using node::BlockAssembler;
using node::CalculateCacheSizes; using node::CalculateCacheSizes;
@ -88,7 +89,7 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
m_args{} m_args{}
{ {
m_node.args = &gArgs; m_node.args = &gArgs;
const std::vector<const char*> arguments = Cat( std::vector<const char*> arguments = Cat(
{ {
"dummy", "dummy",
"-printtoconsole=0", "-printtoconsole=0",
@ -100,6 +101,9 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
"-debugexclude=leveldb", "-debugexclude=leveldb",
}, },
extra_args); extra_args);
if (G_TEST_COMMAND_LINE_ARGUMENTS) {
arguments = Cat(arguments, G_TEST_COMMAND_LINE_ARGUMENTS());
}
util::ThreadRename("test"); util::ThreadRename("test");
fs::create_directories(m_path_root); fs::create_directories(m_path_root);
m_args.ForceSetArg("-datadir", fs::PathToString(m_path_root)); m_args.ForceSetArg("-datadir", fs::PathToString(m_path_root));
@ -108,9 +112,10 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
{ {
SetupServerArgs(*m_node.args); SetupServerArgs(*m_node.args);
std::string error; std::string error;
const bool success{m_node.args->ParseParameters(arguments.size(), arguments.data(), error)}; if (!m_node.args->ParseParameters(arguments.size(), arguments.data(), error)) {
assert(success); m_node.args->ClearArgs();
assert(error.empty()); throw std::runtime_error{error};
}
} }
SelectParams(chainName); SelectParams(chainName);
SeedInsecureRand(); SeedInsecureRand();
@ -218,7 +223,9 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", state.ToString())); throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", state.ToString()));
} }
m_node.addrman = std::make_unique<AddrMan>(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/0); m_node.addrman = std::make_unique<AddrMan>(/*asmap=*/std::vector<bool>(),
/*deterministic=*/false,
m_node.args->GetIntArg("-checkaddrman", 0));
m_node.banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME); m_node.banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
m_node.connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman); // Deterministic randomness for tests. m_node.connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman); // Deterministic randomness for tests.
m_node.peerman = PeerManager::make(chainparams, *m_node.connman, *m_node.addrman, m_node.peerman = PeerManager::make(chainparams, *m_node.connman, *m_node.addrman,

View file

@ -19,12 +19,16 @@
#include <util/string.h> #include <util/string.h>
#include <util/vector.h> #include <util/vector.h>
#include <functional>
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>
/** This is connected to the logger. Can be used to redirect logs to any other log */ /** This is connected to the logger. Can be used to redirect logs to any other log */
extern const std::function<void(const std::string&)> G_TEST_LOG_FUN; extern const std::function<void(const std::string&)> G_TEST_LOG_FUN;
/** Retrieve the command line arguments. */
extern const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUMENTS;
// Enable BOOST_CHECK_EQUAL for enum class types // Enable BOOST_CHECK_EQUAL for enum class types
namespace std { namespace std {
template <typename T> template <typename T>