LCOV - code coverage report
Current view: top level - src/test/fuzz - addrman.cpp (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 0.0 % 170 0
Test Date: 2024-08-28 04:44:32 Functions: 0.0 % 23 0
Branches: 0.0 % 242 0

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2020-2022 The Bitcoin Core developers
       2                 :             : // Distributed under the MIT software license, see the accompanying
       3                 :             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4                 :             : 
       5                 :             : #include <addrdb.h>
       6                 :             : #include <addrman.h>
       7                 :             : #include <addrman_impl.h>
       8                 :             : #include <chainparams.h>
       9                 :             : #include <common/args.h>
      10                 :             : #include <merkleblock.h>
      11                 :             : #include <random.h>
      12                 :             : #include <test/fuzz/FuzzedDataProvider.h>
      13                 :             : #include <test/fuzz/fuzz.h>
      14                 :             : #include <test/fuzz/util.h>
      15                 :             : #include <test/fuzz/util/net.h>
      16                 :             : #include <test/util/setup_common.h>
      17                 :             : #include <time.h>
      18                 :             : #include <util/asmap.h>
      19                 :             : #include <util/chaintype.h>
      20                 :             : 
      21                 :             : #include <cassert>
      22                 :             : #include <cstdint>
      23                 :             : #include <optional>
      24                 :             : #include <string>
      25                 :             : #include <vector>
      26                 :             : 
      27                 :             : namespace {
      28                 :             : const BasicTestingSetup* g_setup;
      29                 :             : 
      30                 :           0 : int32_t GetCheckRatio()
      31                 :             : {
      32   [ #  #  #  # ]:           0 :     return std::clamp<int32_t>(g_setup->m_node.args->GetIntArg("-checkaddrman", 0), 0, 1000000);
      33                 :             : }
      34                 :             : } // namespace
      35                 :             : 
      36                 :           0 : void initialize_addrman()
      37                 :             : {
      38   [ #  #  #  # ]:           0 :     static const auto testing_setup = MakeNoLogFileContext<>(ChainType::REGTEST);
      39                 :           0 :     g_setup = testing_setup.get();
      40         [ #  # ]:           0 : }
      41                 :             : 
      42                 :           0 : [[nodiscard]] inline NetGroupManager ConsumeNetGroupManager(FuzzedDataProvider& fuzzed_data_provider) noexcept
      43                 :             : {
      44                 :           0 :     std::vector<bool> asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider);
      45         [ #  # ]:           0 :     if (!SanityCheckASMap(asmap, 128)) asmap.clear();
      46                 :           0 :     return NetGroupManager(asmap);
      47                 :           0 : }
      48                 :             : 
      49         [ #  # ]:           0 : FUZZ_TARGET(data_stream_addr_man, .init = initialize_addrman)
      50                 :             : {
      51                 :           0 :     FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
      52                 :           0 :     DataStream data_stream = ConsumeDataStream(fuzzed_data_provider);
      53                 :           0 :     NetGroupManager netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)};
      54   [ #  #  #  # ]:           0 :     AddrMan addr_man(netgroupman, /*deterministic=*/false, GetCheckRatio());
      55                 :           0 :     try {
      56         [ #  # ]:           0 :         ReadFromStream(addr_man, data_stream);
      57         [ -  - ]:           0 :     } catch (const std::exception&) {
      58                 :           0 :     }
      59                 :           0 : }
      60                 :             : 
      61                 :             : /**
      62                 :             :  * Generate a random address. Always returns a valid address.
      63                 :             :  */
      64                 :           0 : CNetAddr RandAddr(FuzzedDataProvider& fuzzed_data_provider, FastRandomContext& fast_random_context)
      65                 :             : {
      66                 :           0 :     CNetAddr addr;
      67   [ #  #  #  # ]:           0 :     assert(!addr.IsValid());
      68   [ #  #  #  #  :           0 :     for (size_t i = 0; i < 8 && !addr.IsValid(); ++i) {
                   #  # ]
      69   [ #  #  #  # ]:           0 :         if (fuzzed_data_provider.remaining_bytes() > 1 && fuzzed_data_provider.ConsumeBool()) {
      70                 :           0 :             addr = ConsumeNetAddr(fuzzed_data_provider);
      71                 :             :         } else {
      72                 :           0 :             addr = ConsumeNetAddr(fuzzed_data_provider, &fast_random_context);
      73                 :             :         }
      74                 :             :     }
      75                 :             : 
      76                 :             :     // Return a dummy IPv4 5.5.5.5 if we generated an invalid address.
      77   [ #  #  #  # ]:           0 :     if (!addr.IsValid()) {
      78                 :           0 :         in_addr v4_addr = {};
      79                 :           0 :         v4_addr.s_addr = 0x05050505;
      80         [ #  # ]:           0 :         addr = CNetAddr{v4_addr};
      81                 :             :     }
      82                 :             : 
      83                 :           0 :     return addr;
      84                 :           0 : }
      85                 :             : 
      86                 :             : /** Fill addrman with lots of addresses from lots of sources.  */
      87                 :           0 : void FillAddrman(AddrMan& addrman, FuzzedDataProvider& fuzzed_data_provider)
      88                 :             : {
      89                 :             :     // Add a fraction of the addresses to the "tried" table.
      90                 :             :     // 0, 1, 2, 3 corresponding to 0%, 100%, 50%, 33%
      91                 :           0 :     const size_t n = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 3);
      92                 :             : 
      93                 :           0 :     const size_t num_sources = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 50);
      94                 :           0 :     CNetAddr prev_source;
      95                 :             :     // Generate a FastRandomContext seed to use inside the loops instead of
      96                 :             :     // fuzzed_data_provider. When fuzzed_data_provider is exhausted it
      97                 :             :     // just returns 0.
      98                 :           0 :     FastRandomContext fast_random_context{ConsumeUInt256(fuzzed_data_provider)};
      99         [ #  # ]:           0 :     for (size_t i = 0; i < num_sources; ++i) {
     100         [ #  # ]:           0 :         const auto source = RandAddr(fuzzed_data_provider, fast_random_context);
     101                 :           0 :         const size_t num_addresses = fast_random_context.randrange(500) + 1; // [1..500]
     102                 :             : 
     103         [ #  # ]:           0 :         for (size_t j = 0; j < num_addresses; ++j) {
     104   [ #  #  #  # ]:           0 :             const auto addr = CAddress{CService{RandAddr(fuzzed_data_provider, fast_random_context), 8333}, NODE_NETWORK};
     105                 :           0 :             const std::chrono::seconds time_penalty{fast_random_context.randrange(100000001)};
     106   [ #  #  #  #  :           0 :             addrman.Add({addr}, source, time_penalty);
             #  #  #  # ]
     107                 :             : 
     108   [ #  #  #  #  :           0 :             if (n > 0 && addrman.Size() % n == 0) {
                   #  # ]
     109         [ #  # ]:           0 :                 addrman.Good(addr, Now<NodeSeconds>());
     110                 :             :             }
     111                 :             : 
     112                 :             :             // Add 10% of the addresses from more than one source.
     113   [ #  #  #  #  :           0 :             if (fast_random_context.randrange(10) == 0 && prev_source.IsValid()) {
                   #  # ]
     114   [ #  #  #  #  :           0 :                 addrman.Add({addr}, prev_source, time_penalty);
             #  #  #  # ]
     115                 :             :             }
     116                 :           0 :         }
     117                 :           0 :         prev_source = source;
     118                 :           0 :     }
     119                 :           0 : }
     120                 :             : 
     121                 :           0 : class AddrManDeterministic : public AddrMan
     122                 :             : {
     123                 :             : public:
     124                 :           0 :     explicit AddrManDeterministic(const NetGroupManager& netgroupman, FuzzedDataProvider& fuzzed_data_provider)
     125                 :           0 :         : AddrMan(netgroupman, /*deterministic=*/true, GetCheckRatio())
     126                 :             :     {
     127   [ #  #  #  # ]:           0 :         WITH_LOCK(m_impl->cs, m_impl->insecure_rand.Reseed(ConsumeUInt256(fuzzed_data_provider)));
     128                 :           0 :     }
     129                 :             : 
     130                 :             :     /**
     131                 :             :      * Compare with another AddrMan.
     132                 :             :      * This compares:
     133                 :             :      * - the values in `mapInfo` (the keys aka ids are ignored)
     134                 :             :      * - vvNew entries refer to the same addresses
     135                 :             :      * - vvTried entries refer to the same addresses
     136                 :             :      */
     137                 :           0 :     bool operator==(const AddrManDeterministic& other) const
     138                 :             :     {
     139         [ #  # ]:           0 :         LOCK2(m_impl->cs, other.m_impl->cs);
     140                 :             : 
     141   [ #  #  #  #  :           0 :         if (m_impl->mapInfo.size() != other.m_impl->mapInfo.size() || m_impl->nNew != other.m_impl->nNew ||
                   #  # ]
     142         [ #  # ]:           0 :             m_impl->nTried != other.m_impl->nTried) {
     143                 :             :             return false;
     144                 :             :         }
     145                 :             : 
     146                 :             :         // Check that all values in `mapInfo` are equal to all values in `other.mapInfo`.
     147                 :             :         // Keys may be different.
     148                 :             : 
     149                 :           0 :         auto addrinfo_hasher = [](const AddrInfo& a) {
     150                 :           0 :             CSipHasher hasher(0, 0);
     151                 :           0 :             auto addr_key = a.GetKey();
     152         [ #  # ]:           0 :             auto source_key = a.source.GetAddrBytes();
     153         [ #  # ]:           0 :             hasher.Write(TicksSinceEpoch<std::chrono::seconds>(a.m_last_success));
     154         [ #  # ]:           0 :             hasher.Write(a.nAttempts);
     155         [ #  # ]:           0 :             hasher.Write(a.nRefCount);
     156         [ #  # ]:           0 :             hasher.Write(a.fInTried);
     157   [ #  #  #  # ]:           0 :             hasher.Write(a.GetNetwork());
     158   [ #  #  #  # ]:           0 :             hasher.Write(a.source.GetNetwork());
     159         [ #  # ]:           0 :             hasher.Write(addr_key.size());
     160         [ #  # ]:           0 :             hasher.Write(source_key.size());
     161   [ #  #  #  # ]:           0 :             hasher.Write(addr_key);
     162         [ #  # ]:           0 :             hasher.Write(source_key);
     163         [ #  # ]:           0 :             return (size_t)hasher.Finalize();
     164                 :           0 :         };
     165                 :             : 
     166                 :           0 :         auto addrinfo_eq = [](const AddrInfo& lhs, const AddrInfo& rhs) {
     167                 :           0 :             return std::tie(static_cast<const CService&>(lhs), lhs.source, lhs.m_last_success, lhs.nAttempts, lhs.nRefCount, lhs.fInTried) ==
     168                 :           0 :                    std::tie(static_cast<const CService&>(rhs), rhs.source, rhs.m_last_success, rhs.nAttempts, rhs.nRefCount, rhs.fInTried);
     169                 :             :         };
     170                 :             : 
     171                 :           0 :         using Addresses = std::unordered_set<AddrInfo, decltype(addrinfo_hasher), decltype(addrinfo_eq)>;
     172                 :             : 
     173         [ #  # ]:           0 :         const size_t num_addresses{m_impl->mapInfo.size()};
     174                 :             : 
     175         [ #  # ]:           0 :         Addresses addresses{num_addresses, addrinfo_hasher, addrinfo_eq};
     176   [ #  #  #  # ]:           0 :         for (const auto& [id, addr] : m_impl->mapInfo) {
     177         [ #  # ]:           0 :             addresses.insert(addr);
     178                 :             :         }
     179                 :             : 
     180         [ #  # ]:           0 :         Addresses other_addresses{num_addresses, addrinfo_hasher, addrinfo_eq};
     181   [ #  #  #  # ]:           0 :         for (const auto& [id, addr] : other.m_impl->mapInfo) {
     182         [ #  # ]:           0 :             other_addresses.insert(addr);
     183                 :             :         }
     184                 :             : 
     185   [ #  #  #  # ]:           0 :         if (addresses != other_addresses) {
     186                 :             :             return false;
     187                 :             :         }
     188                 :             : 
     189                 :           0 :         auto IdsReferToSameAddress = [&](int id, int other_id) EXCLUSIVE_LOCKS_REQUIRED(m_impl->cs, other.m_impl->cs) {
     190   [ #  #  #  # ]:           0 :             if (id == -1 && other_id == -1) {
     191                 :             :                 return true;
     192                 :             :             }
     193   [ #  #  #  #  :           0 :             if ((id == -1 && other_id != -1) || (id != -1 && other_id == -1)) {
             #  #  #  # ]
     194                 :             :                 return false;
     195                 :             :             }
     196                 :           0 :             return m_impl->mapInfo.at(id) == other.m_impl->mapInfo.at(other_id);
     197                 :           0 :         };
     198                 :             : 
     199                 :             :         // Check that `vvNew` contains the same addresses as `other.vvNew`. Notice - `vvNew[i][j]`
     200                 :             :         // contains just an id and the address is to be found in `mapInfo.at(id)`. The ids
     201                 :             :         // themselves may differ between `vvNew` and `other.vvNew`.
     202         [ #  # ]:           0 :         for (size_t i = 0; i < ADDRMAN_NEW_BUCKET_COUNT; ++i) {
     203         [ #  # ]:           0 :             for (size_t j = 0; j < ADDRMAN_BUCKET_SIZE; ++j) {
     204   [ #  #  #  # ]:           0 :                 if (!IdsReferToSameAddress(m_impl->vvNew[i][j], other.m_impl->vvNew[i][j])) {
     205                 :             :                     return false;
     206                 :             :                 }
     207                 :             :             }
     208                 :             :         }
     209                 :             : 
     210                 :             :         // Same for `vvTried`.
     211         [ #  # ]:           0 :         for (size_t i = 0; i < ADDRMAN_TRIED_BUCKET_COUNT; ++i) {
     212         [ #  # ]:           0 :             for (size_t j = 0; j < ADDRMAN_BUCKET_SIZE; ++j) {
     213   [ #  #  #  # ]:           0 :                 if (!IdsReferToSameAddress(m_impl->vvTried[i][j], other.m_impl->vvTried[i][j])) {
     214                 :             :                     return false;
     215                 :             :                 }
     216                 :             :             }
     217                 :             :         }
     218                 :             : 
     219                 :             :         return true;
     220         [ #  # ]:           0 :     }
     221                 :             : };
     222                 :             : 
     223         [ #  # ]:           0 : FUZZ_TARGET(addrman, .init = initialize_addrman)
     224                 :             : {
     225                 :           0 :     FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
     226                 :           0 :     SetMockTime(ConsumeTime(fuzzed_data_provider));
     227                 :           0 :     NetGroupManager netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)};
     228         [ #  # ]:           0 :     auto addr_man_ptr = std::make_unique<AddrManDeterministic>(netgroupman, fuzzed_data_provider);
     229         [ #  # ]:           0 :     if (fuzzed_data_provider.ConsumeBool()) {
     230                 :           0 :         const std::vector<uint8_t> serialized_data{ConsumeRandomLengthByteVector(fuzzed_data_provider)};
     231         [ #  # ]:           0 :         DataStream ds{serialized_data};
     232                 :           0 :         try {
     233         [ #  # ]:           0 :             ds >> *addr_man_ptr;
     234         [ -  - ]:           0 :         } catch (const std::ios_base::failure&) {
     235         [ -  - ]:           0 :             addr_man_ptr = std::make_unique<AddrManDeterministic>(netgroupman, fuzzed_data_provider);
     236                 :           0 :         }
     237                 :           0 :     }
     238                 :           0 :     AddrManDeterministic& addr_man = *addr_man_ptr;
     239   [ #  #  #  # ]:           0 :     LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
     240         [ #  # ]:           0 :         CallOneOf(
     241                 :             :             fuzzed_data_provider,
     242                 :           0 :             [&] {
     243                 :           0 :                 addr_man.ResolveCollisions();
     244                 :           0 :             },
     245                 :           0 :             [&] {
     246                 :           0 :                 (void)addr_man.SelectTriedCollision();
     247                 :           0 :             },
     248                 :           0 :             [&] {
     249                 :           0 :                 std::vector<CAddress> addresses;
     250   [ #  #  #  # ]:           0 :                 LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
     251         [ #  # ]:           0 :                     addresses.push_back(ConsumeAddress(fuzzed_data_provider));
     252                 :             :                 }
     253         [ #  # ]:           0 :                 addr_man.Add(addresses, ConsumeNetAddr(fuzzed_data_provider), std::chrono::seconds{ConsumeTime(fuzzed_data_provider, 0, 100000000)});
     254                 :           0 :             },
     255                 :           0 :             [&] {
     256         [ #  # ]:           0 :                 addr_man.Good(ConsumeService(fuzzed_data_provider), NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
     257                 :           0 :             },
     258                 :           0 :             [&] {
     259         [ #  # ]:           0 :                 addr_man.Attempt(ConsumeService(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool(), NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
     260                 :           0 :             },
     261                 :           0 :             [&] {
     262         [ #  # ]:           0 :                 addr_man.Connected(ConsumeService(fuzzed_data_provider), NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
     263                 :           0 :             },
     264                 :           0 :             [&] {
     265         [ #  # ]:           0 :                 addr_man.SetServices(ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS));
     266                 :           0 :             });
     267                 :             :     }
     268                 :           0 :     const AddrMan& const_addr_man{addr_man};
     269                 :           0 :     std::optional<Network> network;
     270         [ #  # ]:           0 :     if (fuzzed_data_provider.ConsumeBool()) {
     271                 :           0 :         network = fuzzed_data_provider.PickValueInArray(ALL_NETWORKS);
     272                 :             :     }
     273         [ #  # ]:           0 :     (void)const_addr_man.GetAddr(
     274                 :             :         /*max_addresses=*/fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096),
     275                 :             :         /*max_pct=*/fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096),
     276                 :             :         network,
     277                 :           0 :         /*filtered=*/fuzzed_data_provider.ConsumeBool());
     278         [ #  # ]:           0 :     (void)const_addr_man.Select(fuzzed_data_provider.ConsumeBool(), network);
     279                 :           0 :     std::optional<bool> in_new;
     280         [ #  # ]:           0 :     if (fuzzed_data_provider.ConsumeBool()) {
     281                 :           0 :         in_new = fuzzed_data_provider.ConsumeBool();
     282                 :             :     }
     283         [ #  # ]:           0 :     (void)const_addr_man.Size(network, in_new);
     284                 :           0 :     DataStream data_stream{};
     285         [ #  # ]:           0 :     data_stream << const_addr_man;
     286                 :           0 : }
     287                 :             : 
     288                 :             : // Check that serialize followed by unserialize produces the same addrman.
     289         [ #  # ]:           0 : FUZZ_TARGET(addrman_serdeser, .init = initialize_addrman)
     290                 :             : {
     291                 :           0 :     FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
     292                 :           0 :     SetMockTime(ConsumeTime(fuzzed_data_provider));
     293                 :             : 
     294                 :           0 :     NetGroupManager netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)};
     295         [ #  # ]:           0 :     AddrManDeterministic addr_man1{netgroupman, fuzzed_data_provider};
     296         [ #  # ]:           0 :     AddrManDeterministic addr_man2{netgroupman, fuzzed_data_provider};
     297                 :             : 
     298                 :           0 :     DataStream data_stream{};
     299                 :             : 
     300         [ #  # ]:           0 :     FillAddrman(addr_man1, fuzzed_data_provider);
     301         [ #  # ]:           0 :     data_stream << addr_man1;
     302         [ #  # ]:           0 :     data_stream >> addr_man2;
     303   [ #  #  #  # ]:           0 :     assert(addr_man1 == addr_man2);
     304                 :           0 : }
        

Generated by: LCOV version 2.0-1