LCOV - code coverage report
Current view: top level - src/test/fuzz - addrman.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 192 201 95.5 %
Date: 2023-10-05 15:40:34 Functions: 31 32 96.9 %
Branches: 201 344 58.4 %

           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         [ +  - ]:        173 : #include <time.h>
      18         [ +  - ]:        173 : #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                 :       3335 : int32_t GetCheckRatio()
      31                 :            : {
      32   [ +  -  +  -  :       3335 :     return std::clamp<int32_t>(g_setup->m_node.args->GetIntArg("-checkaddrman", 0), 0, 1000000);
                   +  - ]
      33                 :          0 : }
      34                 :            : } // namespace
      35                 :            : 
      36                 :          3 : void initialize_addrman()
      37                 :            : {
      38   [ +  -  -  +  :          3 :     static const auto testing_setup = MakeNoLogFileContext<>(ChainType::REGTEST);
                   +  - ]
      39                 :          3 :     g_setup = testing_setup.get();
      40                 :          3 : }
      41                 :            : 
      42                 :       2031 : [[nodiscard]] inline NetGroupManager ConsumeNetGroupManager(FuzzedDataProvider& fuzzed_data_provider) noexcept
      43                 :            : {
      44                 :       2031 :     std::vector<bool> asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider);
      45   [ +  -  +  + ]:       2031 :     if (!SanityCheckASMap(asmap, 128)) asmap.clear();
      46   [ +  -  +  - ]:       2031 :     return NetGroupManager(asmap);
      47                 :       2031 : }
      48                 :            : 
      49   [ +  -  -  + ]:        586 : FUZZ_TARGET(data_stream_addr_man, .init = initialize_addrman)
      50                 :            : {
      51                 :        240 :     FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
      52                 :        240 :     DataStream data_stream = ConsumeDataStream(fuzzed_data_provider);
      53                 :        240 :     NetGroupManager netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)};
      54   [ +  -  +  - ]:        240 :     AddrMan addr_man(netgroupman, /*deterministic=*/false, GetCheckRatio());
      55                 :            :     try {
      56         [ +  + ]:        240 :         ReadFromStream(addr_man, data_stream);
      57         [ -  + ]:        240 :     } catch (const std::exception&) {
      58         [ -  + ]:        227 :     }
      59                 :        467 : }
      60                 :            : 
      61                 :            : /**
      62                 :            :  * Generate a random address. Always returns a valid address.
      63                 :            :  */
      64                 :    5281745 : CNetAddr RandAddr(FuzzedDataProvider& fuzzed_data_provider, FastRandomContext& fast_random_context)
      65                 :            : {
      66                 :    5281745 :     CNetAddr addr;
      67   [ +  -  +  +  :    5281745 :     if (fuzzed_data_provider.remaining_bytes() > 1 && fuzzed_data_provider.ConsumeBool()) {
             +  -  +  + ]
      68                 :     812319 :         addr = ConsumeNetAddr(fuzzed_data_provider);
      69                 :     812319 :     } else {
      70                 :            :         // The networks [1..6] correspond to CNetAddr::BIP155Network (private).
      71   [ +  +  -  +  :    4469426 :         static const std::map<uint8_t, uint8_t> net_len_map = {{1, ADDR_IPV4_SIZE},
             +  -  +  - ]
      72         [ +  - ]:          1 :                                                                {2, ADDR_IPV6_SIZE},
      73         [ +  - ]:          1 :                                                                {4, ADDR_TORV3_SIZE},
      74         [ +  - ]:        174 :                                                                {5, ADDR_I2P_SIZE},
      75         [ +  - ]:          1 :                                                                {6, ADDR_CJDNS_SIZE}};
      76                 :    4469426 :         uint8_t net = fast_random_context.randrange(5) + 1; // [1..5]
      77         [ +  + ]:    4469426 :         if (net == 3) {
      78                 :     893929 :             net = 6;
      79                 :     893929 :         }
      80                 :            : 
      81         [ +  - ]:    4469426 :         DataStream s{};
      82                 :            : 
      83   [ +  -  +  - ]:    4469599 :         s << net;
      84   [ +  -  +  -  :    4469426 :         s << fast_random_context.randbytes(net_len_map.at(net));
                   +  - ]
      85                 :            : 
      86   [ +  -  +  - ]:    4469426 :         s >> CAddress::V2_NETWORK(addr);
      87                 :    4469426 :     }
      88                 :            : 
      89                 :            :     // Return a dummy IPv4 5.5.5.5 if we generated an invalid address.
      90   [ +  -  +  + ]:    5281745 :     if (!addr.IsValid()) {
      91                 :     968304 :         in_addr v4_addr = {};
      92                 :     968304 :         v4_addr.s_addr = 0x05050505;
      93         [ +  - ]:     968304 :         addr = CNetAddr{v4_addr};
      94                 :     968304 :     }
      95                 :            : 
      96                 :    5281745 :     return addr;
      97         [ +  - ]:    5281745 : }
      98                 :            : 
      99                 :            : /** Fill addrman with lots of addresses from lots of sources.  */
     100                 :        789 : void FillAddrman(AddrMan& addrman, FuzzedDataProvider& fuzzed_data_provider)
     101                 :            : {
     102                 :            :     // Add a fraction of the addresses to the "tried" table.
     103                 :            :     // 0, 1, 2, 3 corresponding to 0%, 100%, 50%, 33%
     104                 :        789 :     const size_t n = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 3);
     105                 :            : 
     106                 :        789 :     const size_t num_sources = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 50);
     107                 :        789 :     CNetAddr prev_source;
     108                 :            :     // Generate a FastRandomContext seed to use inside the loops instead of
     109                 :            :     // fuzzed_data_provider. When fuzzed_data_provider is exhausted it
     110                 :            :     // just returns 0.
     111                 :        789 :     FastRandomContext fast_random_context{ConsumeUInt256(fuzzed_data_provider)};
     112         [ +  + ]:      21696 :     for (size_t i = 0; i < num_sources; ++i) {
     113         [ +  - ]:      20907 :         const auto source = RandAddr(fuzzed_data_provider, fast_random_context);
     114                 :      20907 :         const size_t num_addresses = fast_random_context.randrange(500) + 1; // [1..500]
     115                 :            : 
     116         [ +  + ]:    5281745 :         for (size_t j = 0; j < num_addresses; ++j) {
     117   [ +  -  +  -  :    5260838 :             const auto addr = CAddress{CService{RandAddr(fuzzed_data_provider, fast_random_context), 8333}, NODE_NETWORK};
                   +  - ]
     118         [ +  - ]:    5260838 :             const std::chrono::seconds time_penalty{fast_random_context.randrange(100000001)};
     119   [ +  -  +  -  :    5260838 :             addrman.Add({addr}, source, time_penalty);
                   +  - ]
     120                 :            : 
     121   [ +  +  +  -  :    5260838 :             if (n > 0 && addrman.Size() % n == 0) {
                   +  + ]
     122   [ +  -  +  - ]:    2931754 :                 addrman.Good(addr, Now<NodeSeconds>());
     123                 :    2931754 :             }
     124                 :            : 
     125                 :            :             // Add 10% of the addresses from more than one source.
     126   [ +  +  +  -  :    5260838 :             if (fast_random_context.randrange(10) == 0 && prev_source.IsValid()) {
                   +  + ]
     127   [ +  -  +  -  :     507027 :                 addrman.Add({addr}, prev_source, time_penalty);
                   +  - ]
     128                 :     507027 :             }
     129                 :    5260838 :         }
     130         [ +  - ]:      20907 :         prev_source = source;
     131                 :      20907 :     }
     132                 :        789 : }
     133                 :            : 
     134                 :            : class AddrManDeterministic : public AddrMan
     135                 :            : {
     136                 :            : public:
     137                 :       3095 :     explicit AddrManDeterministic(const NetGroupManager& netgroupman, FuzzedDataProvider& fuzzed_data_provider)
     138                 :       3095 :         : AddrMan(netgroupman, /*deterministic=*/true, GetCheckRatio())
     139                 :            :     {
     140   [ +  -  +  - ]:       6190 :         WITH_LOCK(m_impl->cs, m_impl->insecure_rand = FastRandomContext{ConsumeUInt256(fuzzed_data_provider)});
     141                 :       3095 :     }
     142                 :            : 
     143                 :            :     /**
     144                 :            :      * Compare with another AddrMan.
     145                 :            :      * This compares:
     146                 :            :      * - the values in `mapInfo` (the keys aka ids are ignored)
     147                 :            :      * - vvNew entries refer to the same addresses
     148                 :            :      * - vvTried entries refer to the same addresses
     149                 :            :      */
     150                 :        789 :     bool operator==(const AddrManDeterministic& other) const
     151                 :            :     {
     152         [ +  - ]:        789 :         LOCK2(m_impl->cs, other.m_impl->cs);
     153                 :            : 
     154   [ +  -  +  -  :        789 :         if (m_impl->mapInfo.size() != other.m_impl->mapInfo.size() || m_impl->nNew != other.m_impl->nNew ||
                   -  + ]
     155                 :        789 :             m_impl->nTried != other.m_impl->nTried) {
     156                 :          0 :             return false;
     157                 :            :         }
     158                 :            : 
     159                 :            :         // Check that all values in `mapInfo` are equal to all values in `other.mapInfo`.
     160                 :            :         // Keys may be different.
     161                 :            : 
     162                 :    6029906 :         auto addrinfo_hasher = [](const AddrInfo& a) {
     163                 :    6029906 :             CSipHasher hasher(0, 0);
     164                 :    6029906 :             auto addr_key = a.GetKey();
     165         [ +  - ]:    6029906 :             auto source_key = a.source.GetAddrBytes();
     166   [ +  -  +  - ]:    6029906 :             hasher.Write(TicksSinceEpoch<std::chrono::seconds>(a.m_last_success));
     167         [ +  - ]:    6029906 :             hasher.Write(a.nAttempts);
     168         [ +  - ]:    6029906 :             hasher.Write(a.nRefCount);
     169         [ +  - ]:    6029906 :             hasher.Write(a.fInTried);
     170   [ +  -  +  - ]:    6029906 :             hasher.Write(a.GetNetwork());
     171   [ +  -  +  - ]:    6029906 :             hasher.Write(a.source.GetNetwork());
     172         [ +  - ]:    6029906 :             hasher.Write(addr_key.size());
     173         [ +  - ]:    6029906 :             hasher.Write(source_key.size());
     174   [ +  -  +  - ]:    6029906 :             hasher.Write(addr_key);
     175   [ +  -  +  - ]:    6029906 :             hasher.Write(source_key);
     176         [ +  - ]:    6029906 :             return (size_t)hasher.Finalize();
     177                 :    6029906 :         };
     178                 :            : 
     179                 :          0 :         auto addrinfo_eq = [](const AddrInfo& lhs, const AddrInfo& rhs) {
     180                 :          0 :             return std::tie(static_cast<const CService&>(lhs), lhs.source, lhs.m_last_success, lhs.nAttempts, lhs.nRefCount, lhs.fInTried) ==
     181                 :          0 :                    std::tie(static_cast<const CService&>(rhs), rhs.source, rhs.m_last_success, rhs.nAttempts, rhs.nRefCount, rhs.fInTried);
     182                 :            :         };
     183                 :            : 
     184                 :            :         using Addresses = std::unordered_set<AddrInfo, decltype(addrinfo_hasher), decltype(addrinfo_eq)>;
     185                 :            : 
     186                 :        789 :         const size_t num_addresses{m_impl->mapInfo.size()};
     187                 :            : 
     188         [ +  - ]:        789 :         Addresses addresses{num_addresses, addrinfo_hasher, addrinfo_eq};
     189         [ +  + ]:    3015742 :         for (const auto& [id, addr] : m_impl->mapInfo) {
     190         [ +  - ]:    3014953 :             addresses.insert(addr);
     191                 :            :         }
     192                 :            : 
     193         [ -  + ]:        789 :         Addresses other_addresses{num_addresses, addrinfo_hasher, addrinfo_eq};
     194         [ +  + ]:    3015742 :         for (const auto& [id, addr] : other.m_impl->mapInfo) {
     195         [ +  - ]:    3014953 :             other_addresses.insert(addr);
     196                 :            :         }
     197                 :            : 
     198   [ +  -  -  + ]:        789 :         if (addresses != other_addresses) {
     199                 :          0 :             return false;
     200                 :            :         }
     201                 :            : 
     202                 :   64635669 :         auto IdsReferToSameAddress = [&](int id, int other_id) EXCLUSIVE_LOCKS_REQUIRED(m_impl->cs, other.m_impl->cs) {
     203   [ +  +  +  - ]:   64634880 :             if (id == -1 && other_id == -1) {
     204                 :   61557528 :                 return true;
     205                 :            :             }
     206   [ -  +  +  -  :    3077352 :             if ((id == -1 && other_id != -1) || (id != -1 && other_id == -1)) {
                   +  - ]
     207                 :          0 :                 return false;
     208                 :            :             }
     209                 :    3077352 :             return m_impl->mapInfo.at(id) == other.m_impl->mapInfo.at(other_id);
     210                 :   64634880 :         };
     211                 :            : 
     212                 :            :         // Check that `vvNew` contains the same addresses as `other.vvNew`. Notice - `vvNew[i][j]`
     213                 :            :         // contains just an id and the address is to be found in `mapInfo.at(id)`. The ids
     214                 :            :         // themselves may differ between `vvNew` and `other.vvNew`.
     215         [ +  + ]:     808725 :         for (size_t i = 0; i < ADDRMAN_NEW_BUCKET_COUNT; ++i) {
     216         [ +  + ]:   52515840 :             for (size_t j = 0; j < ADDRMAN_BUCKET_SIZE; ++j) {
     217   [ +  -  +  - ]:   51707904 :                 if (!IdsReferToSameAddress(m_impl->vvNew[i][j], other.m_impl->vvNew[i][j])) {
     218                 :          0 :                     return false;
     219                 :            :                 }
     220                 :   51707904 :             }
     221                 :     807936 :         }
     222                 :            : 
     223                 :            :         // Same for `vvTried`.
     224         [ +  + ]:     202773 :         for (size_t i = 0; i < ADDRMAN_TRIED_BUCKET_COUNT; ++i) {
     225         [ +  + ]:   13128960 :             for (size_t j = 0; j < ADDRMAN_BUCKET_SIZE; ++j) {
     226   [ +  -  +  - ]:   12926976 :                 if (!IdsReferToSameAddress(m_impl->vvTried[i][j], other.m_impl->vvTried[i][j])) {
     227                 :          0 :                     return false;
     228                 :            :                 }
     229                 :   12926976 :             }
     230                 :     201984 :         }
     231                 :            : 
     232                 :        789 :         return true;
     233                 :        789 :     }
     234                 :            : };
     235                 :            : 
     236   [ +  -  -  + ]:       1348 : FUZZ_TARGET(addrman, .init = initialize_addrman)
     237                 :            : {
     238                 :       1002 :     FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
     239                 :       1002 :     SetMockTime(ConsumeTime(fuzzed_data_provider));
     240                 :       1002 :     NetGroupManager netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)};
     241         [ +  - ]:       1002 :     auto addr_man_ptr = std::make_unique<AddrManDeterministic>(netgroupman, fuzzed_data_provider);
     242   [ +  -  +  + ]:       1002 :     if (fuzzed_data_provider.ConsumeBool()) {
     243                 :        608 :         const std::vector<uint8_t> serialized_data{ConsumeRandomLengthByteVector(fuzzed_data_provider)};
     244   [ +  -  +  - ]:        608 :         DataStream ds{serialized_data};
     245                 :            :         try {
     246   [ +  -  +  + ]:        608 :             ds >> *addr_man_ptr;
     247         [ -  + ]:        608 :         } catch (const std::ios_base::failure&) {
     248         [ +  - ]:        515 :             addr_man_ptr = std::make_unique<AddrManDeterministic>(netgroupman, fuzzed_data_provider);
     249   [ +  -  #  # ]:        515 :         }
     250                 :        608 :     }
     251         [ +  - ]:       1002 :     AddrManDeterministic& addr_man = *addr_man_ptr;
     252   [ +  +  +  + ]:      59176 :     LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
     253         [ +  + ]:      57172 :         CallOneOf(
     254                 :            :             fuzzed_data_provider,
     255                 :      58420 :             [&] {
     256                 :       1248 :                 addr_man.ResolveCollisions();
     257                 :       1248 :             },
     258                 :      59737 :             [&] {
     259                 :       2565 :                 (void)addr_man.SelectTriedCollision();
     260                 :       2565 :             },
     261                 :      59180 :             [&] {
     262                 :       2008 :                 std::vector<CAddress> addresses;
     263   [ +  -  +  +  :     865720 :                 LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
                   +  + ]
     264         [ +  - ]:     863712 :                     addresses.push_back(ConsumeAddress(fuzzed_data_provider));
     265                 :     863712 :                 }
     266   [ +  -  +  -  :       2008 :                 addr_man.Add(addresses, ConsumeNetAddr(fuzzed_data_provider), std::chrono::seconds{ConsumeTime(fuzzed_data_provider, 0, 100000000)});
             +  -  +  - ]
     267                 :       2008 :             },
     268                 :     105459 :             [&] {
     269   [ +  -  +  -  :      48287 :                 addr_man.Good(ConsumeService(fuzzed_data_provider), NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
                   +  - ]
     270                 :      48287 :             },
     271                 :      58229 :             [&] {
     272   [ +  -  +  -  :       1057 :                 addr_man.Attempt(ConsumeService(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool(), NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
             +  -  +  - ]
     273                 :       1057 :             },
     274                 :      57403 :             [&] {
     275   [ +  -  +  -  :        231 :                 addr_man.Connected(ConsumeService(fuzzed_data_provider), NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
                   +  - ]
     276                 :        231 :             },
     277                 :      59950 :             [&] {
     278         [ +  - ]:       2778 :                 addr_man.SetServices(ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS));
     279                 :       2778 :             });
     280                 :      58174 :     }
     281                 :       1002 :     const AddrMan& const_addr_man{addr_man};
     282                 :       1002 :     std::optional<Network> network;
     283   [ +  -  +  + ]:       1002 :     if (fuzzed_data_provider.ConsumeBool()) {
     284   [ +  -  +  - ]:        149 :         network = fuzzed_data_provider.PickValueInArray(ALL_NETWORKS);
     285                 :        149 :     }
     286         [ +  - ]:       2004 :     (void)const_addr_man.GetAddr(
     287         [ +  - ]:       1002 :         /*max_addresses=*/fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096),
     288         [ +  - ]:       1002 :         /*max_pct=*/fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096),
     289                 :       1002 :         network);
     290   [ +  -  +  - ]:       1002 :     (void)const_addr_man.Select(fuzzed_data_provider.ConsumeBool(), network);
     291                 :       1002 :     std::optional<bool> in_new;
     292   [ +  -  +  + ]:       1002 :     if (fuzzed_data_provider.ConsumeBool()) {
     293   [ +  -  +  - ]:        147 :         in_new = fuzzed_data_provider.ConsumeBool();
     294                 :        147 :     }
     295         [ +  - ]:       1002 :     (void)const_addr_man.Size(network, in_new);
     296         [ +  + ]:       1002 :     DataStream data_stream{};
     297         [ +  - ]:       1002 :     data_stream << const_addr_man;
     298                 :       5525 : }
     299                 :            : 
     300                 :            : // Check that serialize followed by unserialize produces the same addrman.
     301   [ +  -  -  + ]:       1135 : FUZZ_TARGET(addrman_serdeser, .init = initialize_addrman)
     302                 :            : {
     303                 :        789 :     FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
     304                 :        789 :     SetMockTime(ConsumeTime(fuzzed_data_provider));
     305                 :            : 
     306                 :        789 :     NetGroupManager netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)};
     307         [ +  - ]:        789 :     AddrManDeterministic addr_man1{netgroupman, fuzzed_data_provider};
     308         [ +  - ]:        789 :     AddrManDeterministic addr_man2{netgroupman, fuzzed_data_provider};
     309                 :            : 
     310         [ +  - ]:        789 :     DataStream data_stream{};
     311                 :            : 
     312         [ +  - ]:        789 :     FillAddrman(addr_man1, fuzzed_data_provider);
     313         [ +  - ]:        789 :     data_stream << addr_man1;
     314         [ +  - ]:        789 :     data_stream >> addr_man2;
     315   [ +  -  +  - ]:        789 :     assert(addr_man1 == addr_man2);
     316                 :        789 : }

Generated by: LCOV version 1.14