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()