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