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