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