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