/ src / test / addrman_tests.cpp
addrman_tests.cpp
   1  // Copyright (c) 2012-present 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 <clientversion.h>
  10  #include <hash.h>
  11  #include <netbase.h>
  12  #include <random.h>
  13  #include <test/data/asmap.raw.h>
  14  #include <test/util/setup_common.h>
  15  #include <test/util/time.h>
  16  #include <util/asmap.h>
  17  #include <util/string.h>
  18  
  19  #include <boost/test/unit_test.hpp>
  20  
  21  #include <cstdint>
  22  #include <optional>
  23  #include <string>
  24  
  25  using namespace std::literals;
  26  using node::NodeContext;
  27  using util::ToString;
  28  
  29  static auto EMPTY_NETGROUPMAN{NetGroupManager::NoAsmap()};
  30  static const bool DETERMINISTIC{true};
  31  
  32  static int32_t GetCheckRatio(const NodeContext& node_ctx)
  33  {
  34      return std::clamp<int32_t>(node_ctx.args->GetIntArg("-checkaddrman", 100), 0, 1000000);
  35  }
  36  
  37  static CNetAddr ResolveIP(const std::string& ip)
  38  {
  39      const std::optional<CNetAddr> addr{LookupHost(ip, false)};
  40      BOOST_CHECK_MESSAGE(addr.has_value(), strprintf("failed to resolve: %s", ip));
  41      return addr.value_or(CNetAddr{});
  42  }
  43  
  44  static CService ResolveService(const std::string& ip, uint16_t port = 0)
  45  {
  46      const std::optional<CService> serv{Lookup(ip, port, false)};
  47      BOOST_CHECK_MESSAGE(serv.has_value(), strprintf("failed to resolve: %s:%i", ip, port));
  48      return serv.value_or(CService{});
  49  }
  50  
  51  BOOST_FIXTURE_TEST_SUITE(addrman_tests, BasicTestingSetup)
  52  
  53  BOOST_AUTO_TEST_CASE(addrman_simple)
  54  {
  55      auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
  56  
  57      CNetAddr source = ResolveIP("252.2.2.2");
  58  
  59      // Test: Does Addrman respond correctly when empty.
  60      BOOST_CHECK_EQUAL(addrman->Size(), 0U);
  61      auto addr_null = addrman->Select().first;
  62      BOOST_CHECK_EQUAL(addr_null.ToStringAddrPort(), "[::]:0");
  63  
  64      // Test: Does Addrman::Add work as expected.
  65      CService addr1 = ResolveService("250.1.1.1", 8333);
  66      BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
  67      BOOST_CHECK_EQUAL(addrman->Size(), 1U);
  68      auto addr_ret1 = addrman->Select().first;
  69      BOOST_CHECK_EQUAL(addr_ret1.ToStringAddrPort(), "250.1.1.1:8333");
  70  
  71      // Test: Does IP address deduplication work correctly.
  72      //  Expected dup IP should not be added.
  73      CService addr1_dup = ResolveService("250.1.1.1", 8333);
  74      BOOST_CHECK(!addrman->Add({CAddress(addr1_dup, NODE_NONE)}, source));
  75      BOOST_CHECK_EQUAL(addrman->Size(), 1U);
  76  
  77  
  78      // Test: New table has one addr and we add a diff addr we should
  79      //  have at least one addr.
  80      // Note that addrman's size cannot be tested reliably after insertion, as
  81      // hash collisions may occur. But we can always be sure of at least one
  82      // success.
  83  
  84      CService addr2 = ResolveService("250.1.1.2", 8333);
  85      BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, source));
  86      BOOST_CHECK(addrman->Size() >= 1);
  87  
  88      // Test: reset addrman and test AddrMan::Add multiple addresses works as expected
  89      addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
  90      std::vector<CAddress> vAddr;
  91      vAddr.emplace_back(ResolveService("250.1.1.3", 8333), NODE_NONE);
  92      vAddr.emplace_back(ResolveService("250.1.1.4", 8333), NODE_NONE);
  93      BOOST_CHECK(addrman->Add(vAddr, source));
  94      BOOST_CHECK(addrman->Size() >= 1);
  95  }
  96  
  97  
  98  BOOST_AUTO_TEST_CASE(addrman_terrible_many_failures)
  99  {
 100      auto now = Now<NodeSeconds>();
 101      SetMockTime(now - (ADDRMAN_MIN_FAIL + 24h));
 102  
 103      auto addrman{std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node))};
 104  
 105      CNetAddr source{ResolveIP("250.1.2.1")};
 106      CAddress addr{CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE)};
 107      addr.nTime = Now<NodeSeconds>();
 108  
 109      BOOST_CHECK(addrman->Add({addr}, source));
 110      BOOST_CHECK(addrman->Good(addr));
 111  
 112      SetMockTime(now);
 113  
 114      CAddress addr_helper{CAddress(ResolveService("251.252.2.3", 8333), NODE_NONE)};
 115      addr_helper.nTime = Now<NodeSeconds>();
 116      BOOST_CHECK(addrman->Add({addr_helper}, source));
 117      BOOST_CHECK(addrman->Good(addr_helper));
 118  
 119      for (int i = 0; i < ADDRMAN_MAX_FAILURES; ++i) {
 120          // Use a time > 60s ago so IsTerrible doesn't bail out at the "tried in the last minute" check
 121          addrman->Attempt(addr, /*fCountFailure=*/true, Now<NodeSeconds>() - 61s);
 122      }
 123  
 124      std::vector<CAddress> filtered{addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt)};
 125      BOOST_CHECK_EQUAL(filtered.size(), 1U);
 126      BOOST_CHECK_EQUAL(filtered[0].ToStringAddrPort(), "251.252.2.3:8333");
 127  
 128      std::vector<CAddress> unfiltered{addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt, /*filtered=*/false)};
 129      BOOST_CHECK_EQUAL(unfiltered.size(), 2U);
 130  }
 131  
 132  
 133  BOOST_AUTO_TEST_CASE(addrman_penalty_self_announcement)
 134  {
 135      SetMockTime(Now<NodeSeconds>());
 136      auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
 137  
 138      const auto base_time{Now<NodeSeconds>() - 10000s};
 139      CService addr1 = ResolveService("250.1.1.1", 8333);
 140      CNetAddr source1 = ResolveIP("250.1.1.1"); // Same as addr1 - self announcement
 141  
 142      CAddress caddr1(addr1, NODE_NONE);
 143      caddr1.nTime = base_time;
 144  
 145      const auto time_penalty{3600s};
 146  
 147      BOOST_CHECK(addrman->Add({caddr1}, source1, time_penalty));
 148  
 149      auto addr_pos1{addrman->FindAddressEntry(caddr1)};
 150      BOOST_REQUIRE(addr_pos1.has_value());
 151  
 152      std::vector<CAddress> addresses{addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt)};
 153      BOOST_REQUIRE_EQUAL(addresses.size(), 1U);
 154  
 155      BOOST_CHECK(addresses[0].nTime == base_time);
 156  
 157      CService addr2{ResolveService("250.1.1.2", 8333)};
 158      CNetAddr source2{ResolveIP("250.1.1.3")}; // Different from addr2 - not self announcement
 159  
 160      CAddress caddr2(addr2, NODE_NONE);
 161      caddr2.nTime = base_time;
 162  
 163      BOOST_CHECK(addrman->Add({caddr2}, source2, time_penalty));
 164  
 165      addresses = addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt);
 166      BOOST_REQUIRE_EQUAL(addresses.size(), 2U);
 167  
 168      CAddress retrieved_addr2{addresses[0]};
 169      BOOST_CHECK(retrieved_addr2.nTime == base_time - time_penalty);
 170  }
 171  
 172  BOOST_AUTO_TEST_CASE(addrman_ports)
 173  {
 174      auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
 175  
 176      CNetAddr source = ResolveIP("252.2.2.2");
 177  
 178      BOOST_CHECK_EQUAL(addrman->Size(), 0U);
 179  
 180      // Test 7; Addr with same IP but diff port does not replace existing addr.
 181      CService addr1 = ResolveService("250.1.1.1", 8333);
 182      BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
 183      BOOST_CHECK_EQUAL(addrman->Size(), 1U);
 184  
 185      CService addr1_port = ResolveService("250.1.1.1", 8334);
 186      BOOST_CHECK(addrman->Add({CAddress(addr1_port, NODE_NONE)}, source));
 187      BOOST_CHECK_EQUAL(addrman->Size(), 2U);
 188      auto addr_ret2 = addrman->Select().first;
 189      BOOST_CHECK(addr_ret2.ToStringAddrPort() == "250.1.1.1:8333" || addr_ret2.ToStringAddrPort() == "250.1.1.1:8334");
 190  
 191      // Test: Add same IP but diff port to tried table; this converts the entry with
 192      // the specified port to tried, but not the other.
 193      addrman->Good(CAddress(addr1_port, NODE_NONE));
 194      BOOST_CHECK_EQUAL(addrman->Size(), 2U);
 195      bool new_only = true;
 196      auto addr_ret3 = addrman->Select(new_only).first;
 197      BOOST_CHECK_EQUAL(addr_ret3.ToStringAddrPort(), "250.1.1.1:8333");
 198  }
 199  
 200  BOOST_AUTO_TEST_CASE(addrman_select)
 201  {
 202      auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
 203      BOOST_CHECK(!addrman->Select(false).first.IsValid());
 204      BOOST_CHECK(!addrman->Select(true).first.IsValid());
 205  
 206      CNetAddr source = ResolveIP("252.2.2.2");
 207  
 208      // Add 1 address to the new table
 209      CService addr1 = ResolveService("250.1.1.1", 8333);
 210      BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
 211      BOOST_CHECK_EQUAL(addrman->Size(), 1U);
 212  
 213      BOOST_CHECK(addrman->Select(/*new_only=*/true).first == addr1);
 214      BOOST_CHECK(addrman->Select(/*new_only=*/false).first == addr1);
 215  
 216      // Move address to the tried table
 217      BOOST_CHECK(addrman->Good(CAddress(addr1, NODE_NONE)));
 218  
 219      BOOST_CHECK_EQUAL(addrman->Size(), 1U);
 220      BOOST_CHECK(!addrman->Select(/*new_only=*/true).first.IsValid());
 221      BOOST_CHECK(addrman->Select().first == addr1);
 222      BOOST_CHECK_EQUAL(addrman->Size(), 1U);
 223  
 224      // Add one address to the new table
 225      CService addr2 = ResolveService("250.3.1.1", 8333);
 226      BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, addr2));
 227      BOOST_CHECK(addrman->Select(/*new_only=*/true).first == addr2);
 228  
 229      // Add two more addresses to the new table
 230      CService addr3 = ResolveService("250.3.2.2", 9999);
 231      CService addr4 = ResolveService("250.3.3.3", 9999);
 232  
 233      BOOST_CHECK(addrman->Add({CAddress(addr3, NODE_NONE)}, addr2));
 234      BOOST_CHECK(addrman->Add({CAddress(addr4, NODE_NONE)}, ResolveService("250.4.1.1", 8333)));
 235  
 236      // Add three addresses to tried table.
 237      CService addr5 = ResolveService("250.4.4.4", 8333);
 238      CService addr6 = ResolveService("250.4.5.5", 7777);
 239      CService addr7 = ResolveService("250.4.6.6", 8333);
 240  
 241      BOOST_CHECK(addrman->Add({CAddress(addr5, NODE_NONE)}, addr3));
 242      BOOST_CHECK(addrman->Good(CAddress(addr5, NODE_NONE)));
 243      BOOST_CHECK(addrman->Add({CAddress(addr6, NODE_NONE)}, addr3));
 244      BOOST_CHECK(addrman->Good(CAddress(addr6, NODE_NONE)));
 245      BOOST_CHECK(addrman->Add({CAddress(addr7, NODE_NONE)}, ResolveService("250.1.1.3", 8333)));
 246      BOOST_CHECK(addrman->Good(CAddress(addr7, NODE_NONE)));
 247  
 248      // 6 addrs + 1 addr from last test = 7.
 249      BOOST_CHECK_EQUAL(addrman->Size(), 7U);
 250  
 251      // Select pulls from new and tried regardless of port number.
 252      std::set<uint16_t> ports;
 253      for (int i = 0; i < 20; ++i) {
 254          ports.insert(addrman->Select().first.GetPort());
 255      }
 256      BOOST_CHECK_EQUAL(ports.size(), 3U);
 257  }
 258  
 259  BOOST_AUTO_TEST_CASE(addrman_select_by_network)
 260  {
 261      auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
 262      BOOST_CHECK(!addrman->Select(/*new_only=*/true, {NET_IPV4}).first.IsValid());
 263      BOOST_CHECK(!addrman->Select(/*new_only=*/false, {NET_IPV4}).first.IsValid());
 264  
 265      // add ipv4 address to the new table
 266      CNetAddr source = ResolveIP("252.2.2.2");
 267      CService addr1 = ResolveService("250.1.1.1", 8333);
 268      BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
 269  
 270      BOOST_CHECK(addrman->Select(/*new_only=*/true, {NET_IPV4}).first == addr1);
 271      BOOST_CHECK(addrman->Select(/*new_only=*/false, {NET_IPV4}).first == addr1);
 272      BOOST_CHECK(!addrman->Select(/*new_only=*/false, {NET_IPV6}).first.IsValid());
 273      BOOST_CHECK(!addrman->Select(/*new_only=*/false, {NET_ONION}).first.IsValid());
 274      BOOST_CHECK(!addrman->Select(/*new_only=*/false, {NET_I2P}).first.IsValid());
 275      BOOST_CHECK(!addrman->Select(/*new_only=*/false, {NET_CJDNS}).first.IsValid());
 276      BOOST_CHECK(!addrman->Select(/*new_only=*/true, {NET_CJDNS}).first.IsValid());
 277      BOOST_CHECK(addrman->Select(/*new_only=*/false).first == addr1);
 278  
 279      // add I2P address to the new table
 280      CAddress i2p_addr;
 281      i2p_addr.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p");
 282      BOOST_CHECK(addrman->Add({i2p_addr}, source));
 283  
 284      BOOST_CHECK(addrman->Select(/*new_only=*/true, {NET_I2P}).first == i2p_addr);
 285      BOOST_CHECK(addrman->Select(/*new_only=*/false, {NET_I2P}).first == i2p_addr);
 286      BOOST_CHECK(addrman->Select(/*new_only=*/false, {NET_IPV4}).first == addr1);
 287      std::unordered_set<Network> nets_with_entries = {NET_IPV4, NET_I2P};
 288      BOOST_CHECK(addrman->Select(/*new_only=*/false, nets_with_entries).first.IsValid());
 289      BOOST_CHECK(!addrman->Select(/*new_only=*/false, {NET_IPV6}).first.IsValid());
 290      BOOST_CHECK(!addrman->Select(/*new_only=*/false, {NET_ONION}).first.IsValid());
 291      BOOST_CHECK(!addrman->Select(/*new_only=*/false, {NET_CJDNS}).first.IsValid());
 292      std::unordered_set<Network> nets_without_entries = {NET_IPV6, NET_ONION, NET_CJDNS};
 293      BOOST_CHECK(!addrman->Select(/*new_only=*/false, nets_without_entries).first.IsValid());
 294  
 295      // bump I2P address to tried table
 296      BOOST_CHECK(addrman->Good(i2p_addr));
 297  
 298      BOOST_CHECK(!addrman->Select(/*new_only=*/true, {NET_I2P}).first.IsValid());
 299      BOOST_CHECK(addrman->Select(/*new_only=*/false, {NET_I2P}).first == i2p_addr);
 300  
 301      // add another I2P address to the new table
 302      CAddress i2p_addr2;
 303      i2p_addr2.SetSpecial("c4gfnttsuwqomiygupdqqqyy5y5emnk5c73hrfvatri67prd7vyq.b32.i2p");
 304      BOOST_CHECK(addrman->Add({i2p_addr2}, source));
 305  
 306      BOOST_CHECK(addrman->Select(/*new_only=*/true, {NET_I2P}).first == i2p_addr2);
 307  
 308      // ensure that both new and tried table are selected from
 309      bool new_selected{false};
 310      bool tried_selected{false};
 311      int counter = 256;
 312  
 313      while (--counter > 0 && (!new_selected || !tried_selected)) {
 314          const CAddress selected{addrman->Select(/*new_only=*/false, {NET_I2P}).first};
 315          BOOST_REQUIRE(selected == i2p_addr || selected == i2p_addr2);
 316          if (selected == i2p_addr) {
 317              tried_selected = true;
 318          } else {
 319              new_selected = true;
 320          }
 321      }
 322  
 323      BOOST_CHECK(new_selected);
 324      BOOST_CHECK(tried_selected);
 325  }
 326  
 327  BOOST_AUTO_TEST_CASE(addrman_select_special)
 328  {
 329      // use a non-deterministic addrman to ensure a passing test isn't due to setup
 330      auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, /*deterministic=*/false, GetCheckRatio(m_node));
 331  
 332      CNetAddr source = ResolveIP("252.2.2.2");
 333  
 334      // add I2P address to the tried table
 335      CAddress i2p_addr;
 336      i2p_addr.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p");
 337      BOOST_CHECK(addrman->Add({i2p_addr}, source));
 338      BOOST_CHECK(addrman->Good(i2p_addr));
 339  
 340      // add ipv4 address to the new table
 341      CService addr1 = ResolveService("250.1.1.3", 8333);
 342      BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
 343  
 344      // since the only ipv4 address is on the new table, ensure that the new
 345      // table gets selected even if new_only is false. if the table was being
 346      // selected at random, this test will sporadically fail
 347      BOOST_CHECK(addrman->Select(/*new_only=*/false, {NET_IPV4}).first == addr1);
 348  }
 349  
 350  BOOST_AUTO_TEST_CASE(addrman_new_collisions)
 351  {
 352      auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
 353  
 354      CNetAddr source = ResolveIP("252.2.2.2");
 355  
 356      uint32_t num_addrs{0};
 357  
 358      BOOST_CHECK_EQUAL(addrman->Size(), num_addrs);
 359  
 360      while (num_addrs < 22) { // Magic number! 250.1.1.1 - 250.1.1.22 do not collide with deterministic key = 1
 361          CService addr = ResolveService("250.1.1." + ToString(++num_addrs));
 362          BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
 363  
 364          // Test: No collision in new table yet.
 365          BOOST_CHECK_EQUAL(addrman->Size(), num_addrs);
 366      }
 367  
 368      // Test: new table collision!
 369      CService addr1 = ResolveService("250.1.1." + ToString(++num_addrs));
 370      uint32_t collisions{1};
 371      BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
 372      BOOST_CHECK_EQUAL(addrman->Size(), num_addrs - collisions);
 373  
 374      CService addr2 = ResolveService("250.1.1." + ToString(++num_addrs));
 375      BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, source));
 376      BOOST_CHECK_EQUAL(addrman->Size(), num_addrs - collisions);
 377  }
 378  
 379  BOOST_AUTO_TEST_CASE(addrman_new_multiplicity)
 380  {
 381      auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
 382      CAddress addr{CAddress(ResolveService("253.3.3.3", 8333), NODE_NONE)};
 383      const auto start_time{Now<NodeSeconds>()};
 384      addr.nTime = start_time;
 385  
 386      // test that multiplicity stays at 1 if nTime doesn't increase
 387      for (unsigned int i = 1; i < 20; ++i) {
 388          std::string addr_ip{ToString(i % 256) + "." + ToString(i >> 8 % 256) + ".1.1"};
 389          CNetAddr source{ResolveIP(addr_ip)};
 390          addrman->Add({addr}, source);
 391      }
 392      AddressPosition addr_pos = addrman->FindAddressEntry(addr).value();
 393      BOOST_CHECK_EQUAL(addr_pos.multiplicity, 1U);
 394      BOOST_CHECK_EQUAL(addrman->Size(), 1U);
 395  
 396      // if nTime increases, an addr can occur in up to 8 buckets
 397      // The acceptance probability decreases exponentially with existing multiplicity -
 398      // choose number of iterations such that it gets to 8 with deterministic addrman.
 399      for (unsigned int i = 1; i < 400; ++i) {
 400          std::string addr_ip{ToString(i % 256) + "." + ToString(i >> 8 % 256) + ".1.1"};
 401          CNetAddr source{ResolveIP(addr_ip)};
 402          addr.nTime = start_time + std::chrono::seconds{i};
 403          addrman->Add({addr}, source);
 404      }
 405      AddressPosition addr_pos_multi = addrman->FindAddressEntry(addr).value();
 406      BOOST_CHECK_EQUAL(addr_pos_multi.multiplicity, 8U);
 407      // multiplicity doesn't affect size
 408      BOOST_CHECK_EQUAL(addrman->Size(), 1U);
 409  }
 410  
 411  BOOST_AUTO_TEST_CASE(addrman_tried_collisions)
 412  {
 413      auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
 414  
 415      CNetAddr source = ResolveIP("252.2.2.2");
 416  
 417      uint32_t num_addrs{0};
 418  
 419      BOOST_CHECK_EQUAL(addrman->Size(), num_addrs);
 420  
 421      while (num_addrs < 35) { // Magic number! 250.1.1.1 - 250.1.1.35 do not collide in tried with deterministic key = 1
 422          CService addr = ResolveService("250.1.1." + ToString(++num_addrs));
 423          BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
 424  
 425          // Test: Add to tried without collision
 426          BOOST_CHECK(addrman->Good(CAddress(addr, NODE_NONE)));
 427  
 428      }
 429  
 430      // Test: Unable to add to tried table due to collision!
 431      CService addr1 = ResolveService("250.1.1." + ToString(++num_addrs));
 432      BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
 433      BOOST_CHECK(!addrman->Good(CAddress(addr1, NODE_NONE)));
 434  
 435      // Test: Add the next address to tried without collision
 436      CService addr2 = ResolveService("250.1.1." + ToString(++num_addrs));
 437      BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, source));
 438      BOOST_CHECK(addrman->Good(CAddress(addr2, NODE_NONE)));
 439  }
 440  
 441  
 442  BOOST_AUTO_TEST_CASE(addrman_getaddr)
 443  {
 444      auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
 445  
 446      // Test: Sanity check, GetAddr should never return anything if addrman
 447      //  is empty.
 448      BOOST_CHECK_EQUAL(addrman->Size(), 0U);
 449      std::vector<CAddress> vAddr1 = addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt);
 450      BOOST_CHECK_EQUAL(vAddr1.size(), 0U);
 451  
 452      CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE);
 453      addr1.nTime = Now<NodeSeconds>(); // Set time so isTerrible = false
 454      CAddress addr2 = CAddress(ResolveService("250.251.2.2", 9999), NODE_NONE);
 455      addr2.nTime = Now<NodeSeconds>();
 456      CAddress addr3 = CAddress(ResolveService("251.252.2.3", 8333), NODE_NONE);
 457      addr3.nTime = Now<NodeSeconds>();
 458      CAddress addr4 = CAddress(ResolveService("252.253.3.4", 8333), NODE_NONE);
 459      addr4.nTime = Now<NodeSeconds>();
 460      CAddress addr5 = CAddress(ResolveService("252.254.4.5", 8333), NODE_NONE);
 461      addr5.nTime = Now<NodeSeconds>();
 462      CNetAddr source1 = ResolveIP("250.1.2.1");
 463      CNetAddr source2 = ResolveIP("250.2.3.3");
 464  
 465      // Test: Ensure GetAddr works with new addresses.
 466      BOOST_CHECK(addrman->Add({addr1, addr3, addr5}, source1));
 467      BOOST_CHECK(addrman->Add({addr2, addr4}, source2));
 468  
 469      BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt).size(), 5U);
 470      // Net processing asks for 23% of addresses. 23% of 5 is 1 rounded down.
 471      BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt).size(), 1U);
 472  
 473      // Test: Ensure GetAddr works with new and tried addresses.
 474      BOOST_CHECK(addrman->Good(CAddress(addr1, NODE_NONE)));
 475      BOOST_CHECK(addrman->Good(CAddress(addr2, NODE_NONE)));
 476      BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt).size(), 5U);
 477      BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt).size(), 1U);
 478  
 479      // Test: Ensure GetAddr still returns 23% when addrman has many addrs.
 480      for (unsigned int i = 1; i < (8 * 256); i++) {
 481          int octet1 = i % 256;
 482          int octet2 = i >> 8 % 256;
 483          std::string strAddr = ToString(octet1) + "." + ToString(octet2) + ".1.23";
 484          CAddress addr = CAddress(ResolveService(strAddr), NODE_NONE);
 485  
 486          // Ensure that for all addrs in addrman, isTerrible == false.
 487          addr.nTime = Now<NodeSeconds>();
 488          addrman->Add({addr}, ResolveIP(strAddr));
 489          if (i % 8 == 0)
 490              addrman->Good(addr);
 491      }
 492      std::vector<CAddress> vAddr = addrman->GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt);
 493  
 494      size_t percent23 = (addrman->Size() * 23) / 100;
 495      BOOST_CHECK_EQUAL(vAddr.size(), percent23);
 496      BOOST_CHECK_EQUAL(vAddr.size(), 461U);
 497      // (addrman.Size() < number of addresses added) due to address collisions.
 498      BOOST_CHECK_EQUAL(addrman->Size(), 2006U);
 499  }
 500  
 501  BOOST_AUTO_TEST_CASE(getaddr_unfiltered)
 502  {
 503      auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
 504  
 505      // Set time on this addr so isTerrible = false
 506      CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE);
 507      addr1.nTime = Now<NodeSeconds>();
 508      // Not setting time so this addr should be isTerrible = true
 509      CAddress addr2 = CAddress(ResolveService("250.251.2.2", 9999), NODE_NONE);
 510  
 511      CNetAddr source = ResolveIP("250.1.2.1");
 512      BOOST_CHECK(addrman->Add({addr1, addr2}, source));
 513  
 514      // Set time on this addr so isTerrible = false
 515      CAddress addr3 = CAddress(ResolveService("250.251.2.3", 9998), NODE_NONE);
 516      addr3.nTime = Now<NodeSeconds>();
 517      addrman->Good(addr3, /*time=*/Now<NodeSeconds>());
 518      BOOST_CHECK(addrman->Add({addr3}, source));
 519      // The time is set, but after ADDRMAN_RETRIES unsuccessful attempts not
 520      // retried in the last minute, this addr should be isTerrible = true
 521      for (size_t i = 0; i < 3; ++i) {
 522          addrman->Attempt(addr3, /*fCountFailure=*/true, /*time=*/Now<NodeSeconds>() - 61s);
 523      }
 524  
 525      // Set time more than 10 minutes in the future (flying DeLorean), so this
 526      // addr should be isTerrible = true
 527      CAddress addr4 = CAddress(ResolveService("250.252.2.4", 9997), NODE_NONE);
 528      addr4.nTime = Now<NodeSeconds>() + 11min;
 529      BOOST_CHECK(addrman->Add({addr4}, source));
 530  
 531      // GetAddr filtered by quality (i.e. not IsTerrible) should only return addr1
 532      BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt).size(), 1U);
 533      // Unfiltered GetAddr should return all addrs
 534      BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt, /*filtered=*/false).size(), 4U);
 535  }
 536  
 537  BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket_legacy)
 538  {
 539      CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE);
 540      CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE);
 541  
 542      CNetAddr source1 = ResolveIP("250.1.1.1");
 543  
 544  
 545      AddrInfo info1 = AddrInfo(addr1, source1);
 546  
 547      uint256 nKey1 = (HashWriter{} << 1).GetHash();
 548      uint256 nKey2 = (HashWriter{} << 2).GetHash();
 549  
 550      BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN), 40);
 551  
 552      // Test: Make sure key actually randomizes bucket placement. A fail on
 553      //  this test could be a security issue.
 554      BOOST_CHECK(info1.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN) != info1.GetTriedBucket(nKey2, EMPTY_NETGROUPMAN));
 555  
 556      // Test: Two addresses with same IP but different ports can map to
 557      //  different buckets because they have different keys.
 558      AddrInfo info2 = AddrInfo(addr2, source1);
 559  
 560      BOOST_CHECK(info1.GetKey() != info2.GetKey());
 561      BOOST_CHECK(info1.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN) != info2.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN));
 562  
 563      std::set<int> buckets;
 564      for (int i = 0; i < 255; i++) {
 565          AddrInfo infoi = AddrInfo(
 566              CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
 567              ResolveIP("250.1.1." + ToString(i)));
 568          int bucket = infoi.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN);
 569          buckets.insert(bucket);
 570      }
 571      // Test: IP addresses in the same /16 prefix should
 572      // never get more than 8 buckets with legacy grouping
 573      BOOST_CHECK_EQUAL(buckets.size(), 8U);
 574  
 575      buckets.clear();
 576      for (int j = 0; j < 255; j++) {
 577          AddrInfo infoj = AddrInfo(
 578              CAddress(ResolveService("250." + ToString(j) + ".1.1"), NODE_NONE),
 579              ResolveIP("250." + ToString(j) + ".1.1"));
 580          int bucket = infoj.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN);
 581          buckets.insert(bucket);
 582      }
 583      // Test: IP addresses in the different /16 prefix should map to more than
 584      // 8 buckets with legacy grouping
 585      BOOST_CHECK_EQUAL(buckets.size(), 160U);
 586  }
 587  
 588  BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy)
 589  {
 590      CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
 591      CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);
 592  
 593      CNetAddr source1 = ResolveIP("250.1.2.1");
 594  
 595      AddrInfo info1 = AddrInfo(addr1, source1);
 596  
 597      uint256 nKey1 = (HashWriter{} << 1).GetHash();
 598      uint256 nKey2 = (HashWriter{} << 2).GetHash();
 599  
 600      // Test: Make sure the buckets are what we expect
 601      BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, EMPTY_NETGROUPMAN), 786);
 602      BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, EMPTY_NETGROUPMAN), 786);
 603  
 604      // Test: Make sure key actually randomizes bucket placement. A fail on
 605      //  this test could be a security issue.
 606      BOOST_CHECK(info1.GetNewBucket(nKey1, EMPTY_NETGROUPMAN) != info1.GetNewBucket(nKey2, EMPTY_NETGROUPMAN));
 607  
 608      // Test: Ports should not affect bucket placement in the addr
 609      AddrInfo info2 = AddrInfo(addr2, source1);
 610      BOOST_CHECK(info1.GetKey() != info2.GetKey());
 611      BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, EMPTY_NETGROUPMAN), info2.GetNewBucket(nKey1, EMPTY_NETGROUPMAN));
 612  
 613      std::set<int> buckets;
 614      for (int i = 0; i < 255; i++) {
 615          AddrInfo infoi = AddrInfo(
 616              CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
 617              ResolveIP("250.1.1." + ToString(i)));
 618          int bucket = infoi.GetNewBucket(nKey1, EMPTY_NETGROUPMAN);
 619          buckets.insert(bucket);
 620      }
 621      // Test: IP addresses in the same group (\16 prefix for IPv4) should
 622      //  always map to the same bucket.
 623      BOOST_CHECK_EQUAL(buckets.size(), 1U);
 624  
 625      buckets.clear();
 626      for (int j = 0; j < 4 * 255; j++) {
 627          AddrInfo infoj = AddrInfo(CAddress(
 628                                          ResolveService(
 629                                              ToString(250 + (j / 255)) + "." + ToString(j % 256) + ".1.1"), NODE_NONE),
 630              ResolveIP("251.4.1.1"));
 631          int bucket = infoj.GetNewBucket(nKey1, EMPTY_NETGROUPMAN);
 632          buckets.insert(bucket);
 633      }
 634      // Test: IP addresses in the same source groups should map to NO MORE
 635      //  than 64 buckets.
 636      BOOST_CHECK(buckets.size() <= 64);
 637  
 638      buckets.clear();
 639      for (int p = 0; p < 255; p++) {
 640          AddrInfo infoj = AddrInfo(
 641              CAddress(ResolveService("250.1.1.1"), NODE_NONE),
 642              ResolveIP("250." + ToString(p) + ".1.1"));
 643          int bucket = infoj.GetNewBucket(nKey1, EMPTY_NETGROUPMAN);
 644          buckets.insert(bucket);
 645      }
 646      // Test: IP addresses in the different source groups should map to MORE
 647      //  than 64 buckets.
 648      BOOST_CHECK(buckets.size() > 64);
 649  }
 650  
 651  // The following three test cases use asmap.raw
 652  // We use an artificial minimal mock mapping
 653  // 250.0.0.0/8 AS1000
 654  // 101.1.0.0/16 AS1
 655  // 101.2.0.0/16 AS2
 656  // 101.3.0.0/16 AS3
 657  // 101.4.0.0/16 AS4
 658  // 101.5.0.0/16 AS5
 659  // 101.6.0.0/16 AS6
 660  // 101.7.0.0/16 AS7
 661  // 101.8.0.0/16 AS8
 662  BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
 663  {
 664      auto ngm_asmap{NetGroupManager::WithEmbeddedAsmap(test::data::asmap)};
 665  
 666      CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE);
 667      CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE);
 668  
 669      CNetAddr source1 = ResolveIP("250.1.1.1");
 670  
 671  
 672      AddrInfo info1 = AddrInfo(addr1, source1);
 673  
 674      uint256 nKey1 = (HashWriter{} << 1).GetHash();
 675      uint256 nKey2 = (HashWriter{} << 2).GetHash();
 676  
 677      BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, ngm_asmap), 236);
 678  
 679      // Test: Make sure key actually randomizes bucket placement. A fail on
 680      //  this test could be a security issue.
 681      BOOST_CHECK(info1.GetTriedBucket(nKey1, ngm_asmap) != info1.GetTriedBucket(nKey2, ngm_asmap));
 682  
 683      // Test: Two addresses with same IP but different ports can map to
 684      //  different buckets because they have different keys.
 685      AddrInfo info2 = AddrInfo(addr2, source1);
 686  
 687      BOOST_CHECK(info1.GetKey() != info2.GetKey());
 688      BOOST_CHECK(info1.GetTriedBucket(nKey1, ngm_asmap) != info2.GetTriedBucket(nKey1, ngm_asmap));
 689  
 690      std::set<int> buckets;
 691      for (int j = 0; j < 255; j++) {
 692          AddrInfo infoj = AddrInfo(
 693              CAddress(ResolveService("101." + ToString(j) + ".1.1"), NODE_NONE),
 694              ResolveIP("101." + ToString(j) + ".1.1"));
 695          int bucket = infoj.GetTriedBucket(nKey1, ngm_asmap);
 696          buckets.insert(bucket);
 697      }
 698      // Test: IP addresses in the different /16 prefix MAY map to more than
 699      // 8 buckets.
 700      BOOST_CHECK(buckets.size() > 8);
 701  
 702      buckets.clear();
 703      for (int j = 0; j < 255; j++) {
 704          AddrInfo infoj = AddrInfo(
 705              CAddress(ResolveService("250." + ToString(j) + ".1.1"), NODE_NONE),
 706              ResolveIP("250." + ToString(j) + ".1.1"));
 707          int bucket = infoj.GetTriedBucket(nKey1, ngm_asmap);
 708          buckets.insert(bucket);
 709      }
 710      // Test: IP addresses in the different /16 prefix MAY NOT map to more than
 711      // 8 buckets.
 712      BOOST_CHECK(buckets.size() == 8);
 713  }
 714  
 715  BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
 716  {
 717      auto ngm_asmap{NetGroupManager::WithEmbeddedAsmap(test::data::asmap)};
 718  
 719      CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
 720      CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);
 721  
 722      CNetAddr source1 = ResolveIP("250.1.2.1");
 723  
 724      AddrInfo info1 = AddrInfo(addr1, source1);
 725  
 726      uint256 nKey1 = (HashWriter{} << 1).GetHash();
 727      uint256 nKey2 = (HashWriter{} << 2).GetHash();
 728  
 729      // Test: Make sure the buckets are what we expect
 730      BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, ngm_asmap), 795);
 731      BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, ngm_asmap), 795);
 732  
 733      // Test: Make sure key actually randomizes bucket placement. A fail on
 734      //  this test could be a security issue.
 735      BOOST_CHECK(info1.GetNewBucket(nKey1, ngm_asmap) != info1.GetNewBucket(nKey2, ngm_asmap));
 736  
 737      // Test: Ports should not affect bucket placement in the addr
 738      AddrInfo info2 = AddrInfo(addr2, source1);
 739      BOOST_CHECK(info1.GetKey() != info2.GetKey());
 740      BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, ngm_asmap), info2.GetNewBucket(nKey1, ngm_asmap));
 741  
 742      std::set<int> buckets;
 743      for (int i = 0; i < 255; i++) {
 744          AddrInfo infoi = AddrInfo(
 745              CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
 746              ResolveIP("250.1.1." + ToString(i)));
 747          int bucket = infoi.GetNewBucket(nKey1, ngm_asmap);
 748          buckets.insert(bucket);
 749      }
 750      // Test: IP addresses in the same /16 prefix
 751      // usually map to the same bucket.
 752      BOOST_CHECK_EQUAL(buckets.size(), 1U);
 753  
 754      buckets.clear();
 755      for (int j = 0; j < 4 * 255; j++) {
 756          AddrInfo infoj = AddrInfo(CAddress(
 757                                          ResolveService(
 758                                              ToString(250 + (j / 255)) + "." + ToString(j % 256) + ".1.1"), NODE_NONE),
 759              ResolveIP("251.4.1.1"));
 760          int bucket = infoj.GetNewBucket(nKey1, ngm_asmap);
 761          buckets.insert(bucket);
 762      }
 763      // Test: IP addresses in the same source /16 prefix should not map to more
 764      // than 64 buckets.
 765      BOOST_CHECK(buckets.size() <= 64);
 766  
 767      buckets.clear();
 768      for (int p = 0; p < 255; p++) {
 769          AddrInfo infoj = AddrInfo(
 770              CAddress(ResolveService("250.1.1.1"), NODE_NONE),
 771              ResolveIP("101." + ToString(p) + ".1.1"));
 772          int bucket = infoj.GetNewBucket(nKey1, ngm_asmap);
 773          buckets.insert(bucket);
 774      }
 775      // Test: IP addresses in the different source /16 prefixes usually map to MORE
 776      // than 1 bucket.
 777      BOOST_CHECK(buckets.size() > 1);
 778  
 779      buckets.clear();
 780      for (int p = 0; p < 255; p++) {
 781          AddrInfo infoj = AddrInfo(
 782              CAddress(ResolveService("250.1.1.1"), NODE_NONE),
 783              ResolveIP("250." + ToString(p) + ".1.1"));
 784          int bucket = infoj.GetNewBucket(nKey1, ngm_asmap);
 785          buckets.insert(bucket);
 786      }
 787      // Test: IP addresses in the different source /16 prefixes sometimes map to NO MORE
 788      // than 1 bucket.
 789      BOOST_CHECK(buckets.size() == 1);
 790  }
 791  
 792  BOOST_AUTO_TEST_CASE(addrman_serialization)
 793  {
 794      auto netgroupman{NetGroupManager::WithEmbeddedAsmap(test::data::asmap)};
 795  
 796      const auto ratio = GetCheckRatio(m_node);
 797      auto addrman_asmap1 = std::make_unique<AddrMan>(netgroupman, DETERMINISTIC, ratio);
 798      auto addrman_asmap1_dup = std::make_unique<AddrMan>(netgroupman, DETERMINISTIC, ratio);
 799      auto addrman_noasmap = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, ratio);
 800  
 801      DataStream stream{};
 802  
 803      CAddress addr = CAddress(ResolveService("250.1.1.1"), NODE_NONE);
 804      CNetAddr default_source;
 805  
 806      addrman_asmap1->Add({addr}, default_source);
 807  
 808      stream << *addrman_asmap1;
 809      // serizalizing/deserializing addrman with the same asmap
 810      stream >> *addrman_asmap1_dup;
 811  
 812      AddressPosition addr_pos1 = addrman_asmap1->FindAddressEntry(addr).value();
 813      AddressPosition addr_pos2 = addrman_asmap1_dup->FindAddressEntry(addr).value();
 814      BOOST_CHECK(addr_pos1.multiplicity != 0);
 815      BOOST_CHECK(addr_pos2.multiplicity != 0);
 816  
 817      BOOST_CHECK(addr_pos1 == addr_pos2);
 818  
 819      // deserializing asmaped peers.dat to non-asmaped addrman
 820      stream << *addrman_asmap1;
 821      stream >> *addrman_noasmap;
 822      AddressPosition addr_pos3 = addrman_noasmap->FindAddressEntry(addr).value();
 823      BOOST_CHECK(addr_pos3.multiplicity != 0);
 824      BOOST_CHECK(addr_pos1.bucket != addr_pos3.bucket);
 825      BOOST_CHECK(addr_pos1.position != addr_pos3.position);
 826  
 827      // deserializing non-asmaped peers.dat to asmaped addrman
 828      addrman_asmap1 = std::make_unique<AddrMan>(netgroupman, DETERMINISTIC, ratio);
 829      addrman_noasmap = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, ratio);
 830      addrman_noasmap->Add({addr}, default_source);
 831      stream << *addrman_noasmap;
 832      stream >> *addrman_asmap1;
 833  
 834      AddressPosition addr_pos4 = addrman_asmap1->FindAddressEntry(addr).value();
 835      BOOST_CHECK(addr_pos4.multiplicity != 0);
 836      BOOST_CHECK(addr_pos4.bucket != addr_pos3.bucket);
 837      BOOST_CHECK(addr_pos4 == addr_pos2);
 838  
 839      // used to map to different buckets, now maps to the same bucket.
 840      addrman_asmap1 = std::make_unique<AddrMan>(netgroupman, DETERMINISTIC, ratio);
 841      addrman_noasmap = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, ratio);
 842      CAddress addr1 = CAddress(ResolveService("250.1.1.1"), NODE_NONE);
 843      CAddress addr2 = CAddress(ResolveService("250.2.1.1"), NODE_NONE);
 844      addrman_noasmap->Add({addr, addr2}, default_source);
 845      AddressPosition addr_pos5 = addrman_noasmap->FindAddressEntry(addr1).value();
 846      AddressPosition addr_pos6 = addrman_noasmap->FindAddressEntry(addr2).value();
 847      BOOST_CHECK(addr_pos5.bucket != addr_pos6.bucket);
 848      stream << *addrman_noasmap;
 849      stream >> *addrman_asmap1;
 850      AddressPosition addr_pos7 = addrman_asmap1->FindAddressEntry(addr1).value();
 851      AddressPosition addr_pos8 = addrman_asmap1->FindAddressEntry(addr2).value();
 852      BOOST_CHECK(addr_pos7.bucket == addr_pos8.bucket);
 853      BOOST_CHECK(addr_pos7.position != addr_pos8.position);
 854  }
 855  
 856  BOOST_AUTO_TEST_CASE(remove_invalid)
 857  {
 858      // Confirm that invalid addresses are ignored in unserialization.
 859  
 860      auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
 861      DataStream stream{};
 862  
 863      const CAddress new1{ResolveService("5.5.5.5"), NODE_NONE};
 864      const CAddress new2{ResolveService("6.6.6.6"), NODE_NONE};
 865      const CAddress tried1{ResolveService("7.7.7.7"), NODE_NONE};
 866      const CAddress tried2{ResolveService("8.8.8.8"), NODE_NONE};
 867  
 868      addrman->Add({new1, tried1, new2, tried2}, CNetAddr{});
 869      addrman->Good(tried1);
 870      addrman->Good(tried2);
 871      BOOST_REQUIRE_EQUAL(addrman->Size(), 4);
 872  
 873      stream << *addrman;
 874  
 875      const std::string str{stream.str()};
 876      size_t pos;
 877  
 878      const char new2_raw[]{6, 6, 6, 6};
 879      const uint8_t new2_raw_replacement[]{0, 0, 0, 0}; // 0.0.0.0 is !IsValid()
 880      pos = str.find(new2_raw, 0, sizeof(new2_raw));
 881      BOOST_REQUIRE(pos != std::string::npos);
 882      BOOST_REQUIRE(pos + sizeof(new2_raw_replacement) <= stream.size());
 883      memcpy(stream.data() + pos, new2_raw_replacement, sizeof(new2_raw_replacement));
 884  
 885      const char tried2_raw[]{8, 8, 8, 8};
 886      const uint8_t tried2_raw_replacement[]{255, 255, 255, 255}; // 255.255.255.255 is !IsValid()
 887      pos = str.find(tried2_raw, 0, sizeof(tried2_raw));
 888      BOOST_REQUIRE(pos != std::string::npos);
 889      BOOST_REQUIRE(pos + sizeof(tried2_raw_replacement) <= stream.size());
 890      memcpy(stream.data() + pos, tried2_raw_replacement, sizeof(tried2_raw_replacement));
 891  
 892      addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
 893      stream >> *addrman;
 894      BOOST_CHECK_EQUAL(addrman->Size(), 2);
 895  }
 896  
 897  BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
 898  {
 899      auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
 900  
 901      BOOST_CHECK(addrman->Size() == 0);
 902  
 903      // Empty addrman should return blank addrman info.
 904      BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
 905  
 906      // Add twenty two addresses.
 907      CNetAddr source = ResolveIP("252.2.2.2");
 908      for (unsigned int i = 1; i < 23; i++) {
 909          CService addr = ResolveService("250.1.1." + ToString(i));
 910          BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
 911  
 912          // No collisions in tried.
 913          BOOST_CHECK(addrman->Good(addr));
 914          BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
 915      }
 916  
 917      // Ensure Good handles duplicates well.
 918      // If an address is a duplicate, Good will return false but will not count it as a collision.
 919      for (unsigned int i = 1; i < 23; i++) {
 920          CService addr = ResolveService("250.1.1." + ToString(i));
 921  
 922          // Unable to add duplicate address to tried table.
 923          BOOST_CHECK(!addrman->Good(addr));
 924  
 925          // Verify duplicate address not marked as a collision.
 926          BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
 927      }
 928  }
 929  
 930  BOOST_AUTO_TEST_CASE(addrman_noevict)
 931  {
 932      auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
 933  
 934      // Add 35 addresses.
 935      CNetAddr source = ResolveIP("252.2.2.2");
 936      for (unsigned int i = 1; i < 36; i++) {
 937          CService addr = ResolveService("250.1.1." + ToString(i));
 938          BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
 939  
 940          // No collision yet.
 941          BOOST_CHECK(addrman->Good(addr));
 942      }
 943  
 944      // Collision in tried table between 36 and 19.
 945      CService addr36 = ResolveService("250.1.1.36");
 946      BOOST_CHECK(addrman->Add({CAddress(addr36, NODE_NONE)}, source));
 947      BOOST_CHECK(!addrman->Good(addr36));
 948      BOOST_CHECK_EQUAL(addrman->SelectTriedCollision().first.ToStringAddrPort(), "250.1.1.19:0");
 949  
 950      // 36 should be discarded and 19 not evicted.
 951      // This means we keep 19 in the tried table and
 952      // 36 stays in the new table.
 953      addrman->ResolveCollisions();
 954      BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
 955  
 956      // Lets create two collisions.
 957      for (unsigned int i = 37; i < 59; i++) {
 958          CService addr = ResolveService("250.1.1." + ToString(i));
 959          BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
 960          BOOST_CHECK(addrman->Good(addr));
 961      }
 962  
 963      // Cause a collision in the tried table.
 964      CService addr59 = ResolveService("250.1.1.59");
 965      BOOST_CHECK(addrman->Add({CAddress(addr59, NODE_NONE)}, source));
 966      BOOST_CHECK(!addrman->Good(addr59));
 967  
 968      BOOST_CHECK_EQUAL(addrman->SelectTriedCollision().first.ToStringAddrPort(), "250.1.1.10:0");
 969  
 970      // Cause a second collision in the new table.
 971      BOOST_CHECK(!addrman->Add({CAddress(addr36, NODE_NONE)}, source));
 972  
 973      // 36 still cannot be moved from new to tried due to colliding with 19
 974      BOOST_CHECK(!addrman->Good(addr36));
 975      BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() != "[::]:0");
 976  
 977      // Resolve all collisions.
 978      addrman->ResolveCollisions();
 979      BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
 980  }
 981  
 982  BOOST_AUTO_TEST_CASE(addrman_evictionworks)
 983  {
 984      auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
 985  
 986      BOOST_CHECK(addrman->Size() == 0);
 987  
 988      // Empty addrman should return blank addrman info.
 989      BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
 990  
 991      // Add 35 addresses
 992      CNetAddr source = ResolveIP("252.2.2.2");
 993      for (unsigned int i = 1; i < 36; i++) {
 994          CService addr = ResolveService("250.1.1." + ToString(i));
 995          BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
 996  
 997          // No collision yet.
 998          BOOST_CHECK(addrman->Good(addr));
 999      }
1000  
1001      // Collision between 36 and 19.
1002      CService addr = ResolveService("250.1.1.36");
1003      BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
1004      BOOST_CHECK(!addrman->Good(addr));
1005  
1006      auto info = addrman->SelectTriedCollision().first;
1007      BOOST_CHECK_EQUAL(info.ToStringAddrPort(), "250.1.1.19:0");
1008  
1009      // Ensure test of address fails, so that it is evicted.
1010      // Update entry in tried by setting last good connection in the deep past.
1011      BOOST_CHECK(!addrman->Good(info, NodeSeconds{1s}));
1012      addrman->Attempt(info, /*fCountFailure=*/false, Now<NodeSeconds>() - 61s);
1013  
1014      // Should swap 36 for 19.
1015      addrman->ResolveCollisions();
1016      BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
1017      AddressPosition addr_pos{addrman->FindAddressEntry(CAddress(addr, NODE_NONE)).value()};
1018      BOOST_CHECK(addr_pos.tried);
1019  
1020      // If 36 was swapped for 19, then adding 36 to tried should fail because we
1021      // are attempting to add a duplicate.
1022      // We check this by verifying Good() returns false and also verifying that
1023      // we have no collisions.
1024      BOOST_CHECK(!addrman->Good(addr));
1025      BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
1026  
1027      // 19 should fail as a collision (not a duplicate) if we now attempt to move
1028      // it to the tried table.
1029      CService addr19 = ResolveService("250.1.1.19");
1030      BOOST_CHECK(!addrman->Good(addr19));
1031      BOOST_CHECK_EQUAL(addrman->SelectTriedCollision().first.ToStringAddrPort(), "250.1.1.36:0");
1032  
1033      // Eviction is also successful if too much time has passed since last try
1034      NodeClockContext clock_ctx{};
1035      clock_ctx += 4h;
1036      addrman->ResolveCollisions();
1037      BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
1038      //Now 19 is in tried again, and 36 back to new
1039      AddressPosition addr_pos19{addrman->FindAddressEntry(CAddress(addr19, NODE_NONE)).value()};
1040      BOOST_CHECK(addr_pos19.tried);
1041      AddressPosition addr_pos36{addrman->FindAddressEntry(CAddress(addr, NODE_NONE)).value()};
1042      BOOST_CHECK(!addr_pos36.tried);
1043  }
1044  
1045  static auto AddrmanToStream(const AddrMan& addrman)
1046  {
1047      DataStream ssPeersIn{};
1048      ssPeersIn << Params().MessageStart();
1049      ssPeersIn << addrman;
1050      return ssPeersIn;
1051  }
1052  
1053  BOOST_AUTO_TEST_CASE(load_addrman)
1054  {
1055      AddrMan addrman{EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node)};
1056  
1057      std::optional<CService> addr1, addr2, addr3, addr4;
1058      addr1 = Lookup("250.7.1.1", 8333, false);
1059      BOOST_CHECK(addr1.has_value());
1060      addr2 = Lookup("250.7.2.2", 9999, false);
1061      BOOST_CHECK(addr2.has_value());
1062      addr3 = Lookup("250.7.3.3", 9999, false);
1063      BOOST_CHECK(addr3.has_value());
1064      addr3 = Lookup("250.7.3.3"s, 9999, false);
1065      BOOST_CHECK(addr3.has_value());
1066      addr4 = Lookup("250.7.3.3\0example.com"s, 9999, false);
1067      BOOST_CHECK(!addr4.has_value());
1068  
1069      // Add three addresses to new table.
1070      const std::optional<CService> source{Lookup("252.5.1.1", 8333, false)};
1071      BOOST_CHECK(source.has_value());
1072      std::vector<CAddress> addresses{CAddress(addr1.value(), NODE_NONE), CAddress(addr2.value(), NODE_NONE), CAddress(addr3.value(), NODE_NONE)};
1073      BOOST_CHECK(addrman.Add(addresses, source.value()));
1074      BOOST_CHECK(addrman.Size() == 3);
1075  
1076      // Test that the de-serialization does not throw an exception.
1077      auto ssPeers1{AddrmanToStream(addrman)};
1078      bool exceptionThrown = false;
1079      AddrMan addrman1{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
1080  
1081      BOOST_CHECK(addrman1.Size() == 0);
1082      try {
1083          unsigned char pchMsgTmp[4];
1084          ssPeers1 >> pchMsgTmp;
1085          ssPeers1 >> addrman1;
1086      } catch (const std::exception&) {
1087          exceptionThrown = true;
1088      }
1089  
1090      BOOST_CHECK(addrman1.Size() == 3);
1091      BOOST_CHECK(exceptionThrown == false);
1092  
1093      // Test that ReadFromStream creates an addrman with the correct number of addrs.
1094      DataStream ssPeers2 = AddrmanToStream(addrman);
1095  
1096      AddrMan addrman2{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
1097      BOOST_CHECK(addrman2.Size() == 0);
1098      ReadFromStream(addrman2, ssPeers2);
1099      BOOST_CHECK(addrman2.Size() == 3);
1100  }
1101  
1102  // Produce a corrupt peers.dat that claims 20 addrs when it only has one addr.
1103  static auto MakeCorruptPeersDat()
1104  {
1105      DataStream s{};
1106      s << ::Params().MessageStart();
1107  
1108      unsigned char nVersion = 1;
1109      s << nVersion;
1110      s << ((unsigned char)32);
1111      s << uint256::ONE;
1112      s << 10; // nNew
1113      s << 10; // nTried
1114  
1115      int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
1116      s << nUBuckets;
1117  
1118      const std::optional<CService> serv{Lookup("252.1.1.1", 7777, false)};
1119      BOOST_REQUIRE(serv.has_value());
1120      CAddress addr = CAddress(serv.value(), NODE_NONE);
1121      std::optional<CNetAddr> resolved{LookupHost("252.2.2.2", false)};
1122      BOOST_REQUIRE(resolved.has_value());
1123      AddrInfo info = AddrInfo(addr, resolved.value());
1124      s << CAddress::V1_DISK(info);
1125  
1126      return s;
1127  }
1128  
1129  BOOST_AUTO_TEST_CASE(load_addrman_corrupted)
1130  {
1131      // Test that the de-serialization of corrupted peers.dat throws an exception.
1132      auto ssPeers1{MakeCorruptPeersDat()};
1133      bool exceptionThrown = false;
1134      AddrMan addrman1{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
1135      BOOST_CHECK(addrman1.Size() == 0);
1136      try {
1137          unsigned char pchMsgTmp[4];
1138          ssPeers1 >> pchMsgTmp;
1139          ssPeers1 >> addrman1;
1140      } catch (const std::exception&) {
1141          exceptionThrown = true;
1142      }
1143      BOOST_CHECK(exceptionThrown);
1144  
1145      // Test that ReadFromStream fails if peers.dat is corrupt
1146      auto ssPeers2{MakeCorruptPeersDat()};
1147  
1148      AddrMan addrman2{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
1149      BOOST_CHECK(addrman2.Size() == 0);
1150      BOOST_CHECK_THROW(ReadFromStream(addrman2, ssPeers2), std::ios_base::failure);
1151  }
1152  
1153  BOOST_AUTO_TEST_CASE(addrman_update_address)
1154  {
1155      // Tests updating nTime via Connected() and nServices via SetServices() and Add()
1156      auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
1157      CNetAddr source{ResolveIP("252.2.2.2")};
1158      CAddress addr{CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE)};
1159  
1160      const auto start_time{Now<NodeSeconds>() - 10000s};
1161      addr.nTime = start_time;
1162      BOOST_CHECK(addrman->Add({addr}, source));
1163      BOOST_CHECK_EQUAL(addrman->Size(), 1U);
1164  
1165      // Updating an addrman entry with a different port doesn't change it
1166      CAddress addr_diff_port{CAddress(ResolveService("250.1.1.1", 8334), NODE_NONE)};
1167      addr_diff_port.nTime = start_time;
1168      addrman->Connected(addr_diff_port);
1169      addrman->SetServices(addr_diff_port, NODE_NETWORK_LIMITED);
1170      std::vector<CAddress> vAddr1{addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt)};
1171      BOOST_CHECK_EQUAL(vAddr1.size(), 1U);
1172      BOOST_CHECK(vAddr1.at(0).nTime == start_time);
1173      BOOST_CHECK_EQUAL(vAddr1.at(0).nServices, NODE_NONE);
1174  
1175      // Updating an addrman entry with the correct port is successful
1176      addrman->Connected(addr);
1177      addrman->SetServices(addr, NODE_NETWORK_LIMITED);
1178      std::vector<CAddress> vAddr2 = addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt);
1179      BOOST_CHECK_EQUAL(vAddr2.size(), 1U);
1180      BOOST_CHECK(vAddr2.at(0).nTime >= start_time + 10000s);
1181      BOOST_CHECK_EQUAL(vAddr2.at(0).nServices, NODE_NETWORK_LIMITED);
1182  
1183      // Updating an existing addr through Add() (used in gossip relay) can add additional services but can't remove existing ones.
1184      CAddress addr_v2{CAddress(ResolveService("250.1.1.1", 8333), NODE_P2P_V2)};
1185      addr_v2.nTime = start_time;
1186      BOOST_CHECK(!addrman->Add({addr_v2}, source));
1187      std::vector<CAddress> vAddr3{addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt)};
1188      BOOST_CHECK_EQUAL(vAddr3.size(), 1U);
1189      BOOST_CHECK_EQUAL(vAddr3.at(0).nServices, NODE_P2P_V2 | NODE_NETWORK_LIMITED);
1190  
1191      // SetServices() (used when we connected to them) overwrites existing service flags
1192      addrman->SetServices(addr, NODE_NETWORK);
1193      std::vector<CAddress> vAddr4{addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt)};
1194      BOOST_CHECK_EQUAL(vAddr4.size(), 1U);
1195      BOOST_CHECK_EQUAL(vAddr4.at(0).nServices, NODE_NETWORK);
1196  
1197      // Promoting to Tried does not affect the service flags
1198      BOOST_CHECK(addrman->Good(addr)); // addr has NODE_NONE
1199      std::vector<CAddress> vAddr5{addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt)};
1200      BOOST_CHECK_EQUAL(vAddr5.size(), 1U);
1201      BOOST_CHECK_EQUAL(vAddr5.at(0).nServices, NODE_NETWORK);
1202  
1203      // Adding service flags even works when the addr is in Tried
1204      BOOST_CHECK(!addrman->Add({addr_v2}, source));
1205      std::vector<CAddress> vAddr6{addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt)};
1206      BOOST_CHECK_EQUAL(vAddr6.size(), 1U);
1207      BOOST_CHECK_EQUAL(vAddr6.at(0).nServices, NODE_NETWORK | NODE_P2P_V2);
1208  }
1209  
1210  BOOST_AUTO_TEST_CASE(addrman_size)
1211  {
1212      auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
1213      const CNetAddr source = ResolveIP("252.2.2.2");
1214  
1215      // empty addrman
1216      BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/std::nullopt), 0U);
1217      BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/std::nullopt), 0U);
1218      BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/true), 0U);
1219      BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/false), 0U);
1220  
1221      // add two ipv4 addresses, one to tried and new
1222      const CAddress addr1{ResolveService("250.1.1.1", 8333), NODE_NONE};
1223      BOOST_CHECK(addrman->Add({addr1}, source));
1224      BOOST_CHECK(addrman->Good(addr1));
1225      const CAddress addr2{ResolveService("250.1.1.2", 8333), NODE_NONE};
1226      BOOST_CHECK(addrman->Add({addr2}, source));
1227  
1228      BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/std::nullopt), 2U);
1229      BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/std::nullopt), 2U);
1230      BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/true), 1U);
1231      BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/false), 1U);
1232      BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/true), 1U);
1233      BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/false), 1U);
1234  
1235      // add one i2p address to new
1236      CService i2p_addr;
1237      i2p_addr.SetSpecial("UDHDrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.I2P");
1238      const CAddress addr3{i2p_addr, NODE_NONE};
1239      BOOST_CHECK(addrman->Add({addr3}, source));
1240      BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/std::nullopt), 3U);
1241      BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/std::nullopt), 2U);
1242      BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_I2P, /*in_new=*/std::nullopt), 1U);
1243      BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_I2P, /*in_new=*/true), 1U);
1244      BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/true), 2U);
1245      BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/false), 1U);
1246  }
1247  
1248  BOOST_AUTO_TEST_SUITE_END()