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