Merge bitcoin/bitcoin#23053: [fuzz] Use public methods in addrman fuzz tests

44452110f0 [fuzz] Update comment in FillAddrman() (John Newbery)
640476eb0e [fuzz] Make Fill() a free function in fuzz/addrman.cpp (John Newbery)
90ad8ad61a [fuzz] Make RandAddr() a free function in fuzz/addrman.cpp (John Newbery)
491975c596 [fuzz] Pass FuzzedDataProvider& into Fill() in addrman fuzz tests (John Newbery)
56303e382e [fuzz] Create a FastRandomContext in addrman fuzz tests (John Newbery)

Pull request description:

  #22974 improved the performance of `CAddrMan::Good()` significantly so that it could be used directly in the fuzz tests, instead of those tests reaching directly into addrman's internal data structures.

  This PR continues the work of making the fuzz tests only use `CAddrMan`'s public methods and pulls the `Fill()` and `RandAddr()` methods from `CAddrManDeterministic` into free functions, since they no longer need access to `CAddrMan` internals.

ACKs for top commit:
  theuni:
    utACK 44452110f0. Agree the failure seems unrelated, looks like some startup race.
  mzumsande:
    ACK 44452110f0
  vasild:
    ACK 44452110f0

Tree-SHA512: fcf994e1dedd0012b77f632720b6423d51ceda4eb85c9efe572f2a1150117f9e511114a5206738dd94409137287577f3b01a9998f5237de845410d3d96e7cb7f
This commit is contained in:
fanquake committed 2021-10-08 12:13:48 +08:00
commit 97e2435ac4
1 file changed
+34 -39
+34 -39
View File
@@ -7,6 +7,7 @@
#include <addrman_impl.h> #include <addrman_impl.h>
#include <chainparams.h> #include <chainparams.h>
#include <merkleblock.h> #include <merkleblock.h>
#include <random.h>
#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>
@@ -35,26 +36,14 @@ FUZZ_TARGET_INIT(data_stream_addr_man, initialize_addrman)
} }
} }
class AddrManDeterministic : public AddrMan
{
public:
FuzzedDataProvider& m_fuzzed_data_provider;
explicit AddrManDeterministic(std::vector<bool> asmap, FuzzedDataProvider& fuzzed_data_provider)
: AddrMan(std::move(asmap), /* deterministic */ true, /* consistency_check_ratio */ 0)
, m_fuzzed_data_provider(fuzzed_data_provider)
{
WITH_LOCK(m_impl->cs, m_impl->insecure_rand = FastRandomContext{ConsumeUInt256(fuzzed_data_provider)});
}
/** /**
* Generate a random address. Always returns a valid address. * Generate a random address. Always returns a valid address.
*/ */
CNetAddr RandAddr() EXCLUSIVE_LOCKS_REQUIRED(m_impl->cs) CNetAddr RandAddr(FuzzedDataProvider& fuzzed_data_provider, FastRandomContext& fast_random_context)
{ {
CNetAddr addr; CNetAddr addr;
if (m_fuzzed_data_provider.remaining_bytes() > 1 && m_fuzzed_data_provider.ConsumeBool()) { if (fuzzed_data_provider.remaining_bytes() > 1 && fuzzed_data_provider.ConsumeBool()) {
addr = ConsumeNetAddr(m_fuzzed_data_provider); addr = ConsumeNetAddr(fuzzed_data_provider);
} else { } else {
// The networks [1..6] correspond to CNetAddr::BIP155Network (private). // The networks [1..6] correspond to CNetAddr::BIP155Network (private).
static const std::map<uint8_t, uint8_t> net_len_map = {{1, ADDR_IPV4_SIZE}, static const std::map<uint8_t, uint8_t> net_len_map = {{1, ADDR_IPV4_SIZE},
@@ -62,7 +51,7 @@ public:
{4, ADDR_TORV3_SIZE}, {4, ADDR_TORV3_SIZE},
{5, ADDR_I2P_SIZE}, {5, ADDR_I2P_SIZE},
{6, ADDR_CJDNS_SIZE}}; {6, ADDR_CJDNS_SIZE}};
uint8_t net = m_impl->insecure_rand.randrange(5) + 1; // [1..5] uint8_t net = fast_random_context.randrange(5) + 1; // [1..5]
if (net == 3) { if (net == 3) {
net = 6; net = 6;
} }
@@ -70,7 +59,7 @@ public:
CDataStream s(SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT); CDataStream s(SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT);
s << net; s << net;
s << m_impl->insecure_rand.randbytes(net_len_map.at(net)); s << fast_random_context.randbytes(net_len_map.at(net));
s >> addr; s >> addr;
} }
@@ -85,44 +74,50 @@ public:
return addr; return addr;
} }
/** /** Fill addrman with lots of addresses from lots of sources. */
* Fill this addrman with lots of addresses from lots of sources. void FillAddrman(AddrMan& addrman, FuzzedDataProvider& fuzzed_data_provider)
*/
void Fill()
{ {
LOCK(m_impl->cs); // Add a fraction of the addresses to the "tried" table.
// Add some of the addresses directly to the "tried" table.
// 0, 1, 2, 3 corresponding to 0%, 100%, 50%, 33% // 0, 1, 2, 3 corresponding to 0%, 100%, 50%, 33%
const size_t n = m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 3); const size_t n = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 3);
const size_t num_sources = m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 50); const size_t num_sources = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 50);
CNetAddr prev_source; CNetAddr prev_source;
// Use insecure_rand inside the loops instead of m_fuzzed_data_provider because when // Generate a FastRandomContext seed to use inside the loops instead of
// the latter is exhausted it just returns 0. // fuzzed_data_provider. When fuzzed_data_provider is exhausted it
// just returns 0.
FastRandomContext fast_random_context{ConsumeUInt256(fuzzed_data_provider)};
for (size_t i = 0; i < num_sources; ++i) { for (size_t i = 0; i < num_sources; ++i) {
const auto source = RandAddr(); const auto source = RandAddr(fuzzed_data_provider, fast_random_context);
const size_t num_addresses = m_impl->insecure_rand.randrange(500) + 1; // [1..500] const size_t num_addresses = fast_random_context.randrange(500) + 1; // [1..500]
for (size_t j = 0; j < num_addresses; ++j) { for (size_t j = 0; j < num_addresses; ++j) {
const auto addr = CAddress{CService{RandAddr(), 8333}, NODE_NETWORK}; const auto addr = CAddress{CService{RandAddr(fuzzed_data_provider, fast_random_context), 8333}, NODE_NETWORK};
const auto time_penalty = m_impl->insecure_rand.randrange(100000001); const auto time_penalty = fast_random_context.randrange(100000001);
m_impl->Add_(addr, source, time_penalty); addrman.Add({addr}, source, time_penalty);
if (n > 0 && m_impl->mapInfo.size() % n == 0) { if (n > 0 && addrman.size() % n == 0) {
m_impl->Good_(addr, false, GetTime()); addrman.Good(addr, GetTime());
} }
// Add 10% of the addresses from more than one source. // Add 10% of the addresses from more than one source.
if (m_impl->insecure_rand.randrange(10) == 0 && prev_source.IsValid()) { if (fast_random_context.randrange(10) == 0 && prev_source.IsValid()) {
m_impl->Add_({addr}, prev_source, time_penalty); addrman.Add({addr}, prev_source, time_penalty);
} }
} }
prev_source = source; prev_source = source;
} }
} }
class AddrManDeterministic : public AddrMan
{
public:
explicit AddrManDeterministic(std::vector<bool> asmap, FuzzedDataProvider& fuzzed_data_provider)
: AddrMan(std::move(asmap), /* deterministic */ true, /* consistency_check_ratio */ 0)
{
WITH_LOCK(m_impl->cs, m_impl->insecure_rand = FastRandomContext{ConsumeUInt256(fuzzed_data_provider)});
}
/** /**
* Compare with another AddrMan. * Compare with another AddrMan.
* This compares: * This compares:
@@ -307,7 +302,7 @@ FUZZ_TARGET_INIT(addrman_serdeser, initialize_addrman)
CDataStream data_stream(SER_NETWORK, PROTOCOL_VERSION); CDataStream data_stream(SER_NETWORK, PROTOCOL_VERSION);
addr_man1.Fill(); FillAddrman(addr_man1, fuzzed_data_provider);
data_stream << addr_man1; data_stream << addr_man1;
data_stream >> addr_man2; data_stream >> addr_man2;
assert(addr_man1 == addr_man2); assert(addr_man1 == addr_man2);