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

This commit is contained in:
Kittywhiskers Van Gogh 2024-09-01 18:17:00 +00:00
parent b30f0fa441
commit cdcaf2278c
No known key found for this signature in database
GPG Key ID: 30CD0C065E5C4AAD
13 changed files with 169 additions and 55 deletions

View File

@ -64,6 +64,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 `dashd` 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

@ -14,6 +14,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;
@ -72,14 +75,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);
@ -91,7 +94,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);
@ -120,7 +123,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

@ -16,6 +16,8 @@
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 fs::path& file, const char* tpl) void GenerateTemplateResults(const std::vector<ankerl::nanobench::Result>& benchmarkResults, const fs::path& file, const char* tpl)

View File

@ -23,6 +23,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>
@ -40,6 +41,8 @@ Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin);
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_dash` has some built-in command-line arguments; for `test_dash` 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_dash --log_level=all --run_test=getarg_tests -- DEBUG_LOG_OUT ```bash
test_dash --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_dash` also accepts the command
redirects the debug log, which would normally go to a file in the test datadir line arguments accepted by `dashd`. Use `--` to separate both types of
arguments:
```bash
test_dash --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_dash --run_test=getarg_tests/doubledash ```bash
test_dash --run_test=getarg_tests/doubledash
```
Run `test_dash --help` for the full list. Run `test_dash --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_dash` executable with `gdb`or `lldb` and For debugging you can launch the `test_dash` 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_dash core gdb src/test/test_dash core
(gbd) bt # produce a backtrace for where a segfault occurred (gbd) bt # produce a backtrace for where a segfault occurred

View File

@ -9,6 +9,7 @@
#include <clientversion.h> #include <clientversion.h>
#include <hash.h> #include <hash.h>
#include <netbase.h> #include <netbase.h>
#include <node/context.h>
#include <random.h> #include <random.h>
#include <test/data/asmap.raw.h> #include <test/data/asmap.raw.h>
#include <test/util/setup_common.h> #include <test/util/setup_common.h>
@ -20,6 +21,14 @@
using namespace std::literals; using namespace std::literals;
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->GetArg("-checkaddrman", 100), 0, 1000000);
}
static CNetAddr ResolveIP(const std::string& ip) static CNetAddr ResolveIP(const std::string& ip)
{ {
CNetAddr addr; CNetAddr addr;
@ -47,17 +56,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");
@ -91,7 +94,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));
@ -101,7 +104,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");
@ -129,7 +132,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");
@ -188,7 +191,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");
@ -217,7 +220,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;
@ -249,7 +252,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");
@ -280,7 +283,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.
@ -601,9 +604,11 @@ BOOST_AUTO_TEST_CASE(addrman_serialization)
{ {
std::vector<bool> asmap1 = FromBytes(raw_tests::asmap, sizeof(raw_tests::asmap) * 8); std::vector<bool> asmap1 = FromBytes(raw_tests::asmap, sizeof(raw_tests::asmap) * 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);
@ -631,8 +636,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;
@ -643,8 +648,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);
@ -663,7 +668,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};
@ -695,14 +700,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);
@ -735,7 +740,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");
@ -787,7 +792,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);
@ -857,8 +862,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));
@ -877,7 +881,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 {
@ -894,7 +898,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);
@ -932,7 +936,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];
@ -948,7 +952,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);
} }
@ -956,7 +960,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->GetArg("-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

@ -11,21 +11,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->GetArg("-checkaddrman", 0));
CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>(), addrman}; CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>(), addrman};
CNetAddr random_netaddr; CNetAddr random_netaddr;
CNode random_node = ConsumeNode(fuzzed_data_provider); CNode random_node = ConsumeNode(fuzzed_data_provider);

View File

@ -21,7 +21,9 @@
#include <psbt.h> #include <psbt.h>
#include <script/sign.h> #include <script/sign.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>
@ -32,8 +34,14 @@
#include <test/fuzz/fuzz.h> #include <test/fuzz/fuzz.h>
namespace {
const BasicTestingSetup* g_setup;
} // namespace
void initialize_deserialize() void initialize_deserialize()
{ {
static const auto testing_setup = MakeNoLogFileContext<>();
g_setup = testing_setup.get();
} }
#define FUZZ_TARGET_DESERIALIZE(name, code) \ #define FUZZ_TARGET_DESERIALIZE(name, code) \
@ -190,7 +198,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->GetArg("-checkaddrman", 0));
DeserializeFromFuzzingInput(buffer, am); DeserializeFromFuzzingInput(buffer, am);
}) })
FUZZ_TARGET_DESERIALIZE(blockheader_deserialize, { FUZZ_TARGET_DESERIALIZE(blockheader_deserialize, {

View File

@ -16,6 +16,7 @@
#include <cstdint> #include <cstdint>
#include <exception> #include <exception>
#include <fstream> #include <fstream>
#include <functional>
#include <memory> #include <memory>
#include <string> #include <string>
#include <unistd.h> #include <unistd.h>
@ -23,6 +24,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;
@ -132,6 +156,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_dash --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

@ -67,6 +67,7 @@
#include <evo/mnhftx.h> #include <evo/mnhftx.h>
#include <evo/specialtx.h> #include <evo/specialtx.h>
#include <stdexcept>
#include <memory> #include <memory>
const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr; const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
@ -140,7 +141,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",
@ -152,6 +153,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));
@ -160,9 +164,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();
@ -179,7 +184,9 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
InitScriptExecutionCache(); InitScriptExecutionCache();
m_node.chain = interfaces::MakeChain(m_node); m_node.chain = interfaces::MakeChain(m_node);
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->GetArg("-checkaddrman", 0));
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.
// while g_wallet_init_interface is init here at very early stage // while g_wallet_init_interface is init here at very early stage

View File

@ -18,6 +18,7 @@
#include <util/string.h> #include <util/string.h>
#include <util/vector.h> #include <util/vector.h>
#include <functional>
#include <stdexcept> #include <stdexcept>
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>
@ -27,6 +28,9 @@ class CChainParams;
/** 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>