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