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