/workdir/bitcoin/src/addrman.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2012 Pieter Wuille |
2 | | // Copyright (c) 2012-2022 The Bitcoin Core developers |
3 | | // Distributed under the MIT software license, see the accompanying |
4 | | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
5 | | |
6 | | #include <config/bitcoin-config.h> // IWYU pragma: keep |
7 | | |
8 | | #include <addrman.h> |
9 | | #include <addrman_impl.h> |
10 | | |
11 | | #include <hash.h> |
12 | | #include <logging.h> |
13 | | #include <logging/timer.h> |
14 | | #include <netaddress.h> |
15 | | #include <protocol.h> |
16 | | #include <random.h> |
17 | | #include <serialize.h> |
18 | | #include <streams.h> |
19 | | #include <tinyformat.h> |
20 | | #include <uint256.h> |
21 | | #include <util/check.h> |
22 | | #include <util/time.h> |
23 | | |
24 | | #include <cmath> |
25 | | #include <optional> |
26 | | |
27 | | /** Over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread */ |
28 | | static constexpr uint32_t ADDRMAN_TRIED_BUCKETS_PER_GROUP{8}; |
29 | | /** Over how many buckets entries with new addresses originating from a single group are spread */ |
30 | | static constexpr uint32_t ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP{64}; |
31 | | /** Maximum number of times an address can occur in the new table */ |
32 | | static constexpr int32_t ADDRMAN_NEW_BUCKETS_PER_ADDRESS{8}; |
33 | | /** How old addresses can maximally be */ |
34 | | static constexpr auto ADDRMAN_HORIZON{30 * 24h}; |
35 | | /** After how many failed attempts we give up on a new node */ |
36 | | static constexpr int32_t ADDRMAN_RETRIES{3}; |
37 | | /** How many successive failures are allowed ... */ |
38 | | static constexpr int32_t ADDRMAN_MAX_FAILURES{10}; |
39 | | /** ... in at least this duration */ |
40 | | static constexpr auto ADDRMAN_MIN_FAIL{7 * 24h}; |
41 | | /** How recent a successful connection should be before we allow an address to be evicted from tried */ |
42 | | static constexpr auto ADDRMAN_REPLACEMENT{4h}; |
43 | | /** The maximum number of tried addr collisions to store */ |
44 | | static constexpr size_t ADDRMAN_SET_TRIED_COLLISION_SIZE{10}; |
45 | | /** The maximum time we'll spend trying to resolve a tried table collision */ |
46 | | static constexpr auto ADDRMAN_TEST_WINDOW{40min}; |
47 | | |
48 | | int AddrInfo::GetTriedBucket(const uint256& nKey, const NetGroupManager& netgroupman) const |
49 | 0 | { |
50 | 0 | uint64_t hash1 = (HashWriter{} << nKey << GetKey()).GetCheapHash(); |
51 | 0 | uint64_t hash2 = (HashWriter{} << nKey << netgroupman.GetGroup(*this) << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetCheapHash(); |
52 | 0 | return hash2 % ADDRMAN_TRIED_BUCKET_COUNT; |
53 | 0 | } |
54 | | |
55 | | int AddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src, const NetGroupManager& netgroupman) const |
56 | 0 | { |
57 | 0 | std::vector<unsigned char> vchSourceGroupKey = netgroupman.GetGroup(src); |
58 | 0 | uint64_t hash1 = (HashWriter{} << nKey << netgroupman.GetGroup(*this) << vchSourceGroupKey).GetCheapHash(); |
59 | 0 | uint64_t hash2 = (HashWriter{} << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)).GetCheapHash(); |
60 | 0 | return hash2 % ADDRMAN_NEW_BUCKET_COUNT; |
61 | 0 | } |
62 | | |
63 | | int AddrInfo::GetBucketPosition(const uint256& nKey, bool fNew, int bucket) const |
64 | 0 | { |
65 | 0 | uint64_t hash1 = (HashWriter{} << nKey << (fNew ? uint8_t{'N'} : uint8_t{'K'}) << bucket << GetKey()).GetCheapHash(); Branch (65:48): [True: 0, False: 0]
|
66 | 0 | return hash1 % ADDRMAN_BUCKET_SIZE; |
67 | 0 | } |
68 | | |
69 | | bool AddrInfo::IsTerrible(NodeSeconds now) const |
70 | 0 | { |
71 | 0 | if (now - m_last_try <= 1min) { // never remove things tried in the last minute Branch (71:9): [True: 0, False: 0]
|
72 | 0 | return false; |
73 | 0 | } |
74 | | |
75 | 0 | if (nTime > now + 10min) { // came in a flying DeLorean Branch (75:9): [True: 0, False: 0]
|
76 | 0 | return true; |
77 | 0 | } |
78 | | |
79 | 0 | if (now - nTime > ADDRMAN_HORIZON) { // not seen in recent history Branch (79:9): [True: 0, False: 0]
|
80 | 0 | return true; |
81 | 0 | } |
82 | | |
83 | 0 | if (TicksSinceEpoch<std::chrono::seconds>(m_last_success) == 0 && nAttempts >= ADDRMAN_RETRIES) { // tried N times and never a success Branch (83:9): [True: 0, False: 0]
Branch (83:71): [True: 0, False: 0]
|
84 | 0 | return true; |
85 | 0 | } |
86 | | |
87 | 0 | if (now - m_last_success > ADDRMAN_MIN_FAIL && nAttempts >= ADDRMAN_MAX_FAILURES) { // N successive failures in the last week Branch (87:9): [True: 0, False: 0]
Branch (87:9): [True: 0, False: 0]
Branch (87:52): [True: 0, False: 0]
|
88 | 0 | return true; |
89 | 0 | } |
90 | | |
91 | 0 | return false; |
92 | 0 | } |
93 | | |
94 | | double AddrInfo::GetChance(NodeSeconds now) const |
95 | 0 | { |
96 | 0 | double fChance = 1.0; |
97 | | |
98 | | // deprioritize very recent attempts away |
99 | 0 | if (now - m_last_try < 10min) { Branch (99:9): [True: 0, False: 0]
|
100 | 0 | fChance *= 0.01; |
101 | 0 | } |
102 | | |
103 | | // deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages. |
104 | 0 | fChance *= pow(0.66, std::min(nAttempts, 8)); |
105 | |
|
106 | 0 | return fChance; |
107 | 0 | } |
108 | | |
109 | | AddrManImpl::AddrManImpl(const NetGroupManager& netgroupman, bool deterministic, int32_t consistency_check_ratio) |
110 | 0 | : insecure_rand{deterministic} |
111 | 0 | , nKey{deterministic ? uint256{1} : insecure_rand.rand256()} Branch (111:12): [True: 0, False: 0]
|
112 | 0 | , m_consistency_check_ratio{consistency_check_ratio} |
113 | 0 | , m_netgroupman{netgroupman} |
114 | 0 | { |
115 | 0 | for (auto& bucket : vvNew) { Branch (115:23): [True: 0, False: 0]
|
116 | 0 | for (auto& entry : bucket) { Branch (116:26): [True: 0, False: 0]
|
117 | 0 | entry = -1; |
118 | 0 | } |
119 | 0 | } |
120 | 0 | for (auto& bucket : vvTried) { Branch (120:23): [True: 0, False: 0]
|
121 | 0 | for (auto& entry : bucket) { Branch (121:26): [True: 0, False: 0]
|
122 | 0 | entry = -1; |
123 | 0 | } |
124 | 0 | } |
125 | 0 | } |
126 | | |
127 | | AddrManImpl::~AddrManImpl() |
128 | 1 | { |
129 | 1 | nKey.SetNull(); |
130 | 1 | } |
131 | | |
132 | | template <typename Stream> |
133 | | void AddrManImpl::Serialize(Stream& s_) const |
134 | 0 | { |
135 | 0 | LOCK(cs); |
136 | | |
137 | | /** |
138 | | * Serialized format. |
139 | | * * format version byte (@see `Format`) |
140 | | * * lowest compatible format version byte. This is used to help old software decide |
141 | | * whether to parse the file. For example: |
142 | | * * Bitcoin Core version N knows how to parse up to format=3. If a new format=4 is |
143 | | * introduced in version N+1 that is compatible with format=3 and it is known that |
144 | | * version N will be able to parse it, then version N+1 will write |
145 | | * (format=4, lowest_compatible=3) in the first two bytes of the file, and so |
146 | | * version N will still try to parse it. |
147 | | * * Bitcoin Core version N+2 introduces a new incompatible format=5. It will write |
148 | | * (format=5, lowest_compatible=5) and so any versions that do not know how to parse |
149 | | * format=5 will not try to read the file. |
150 | | * * nKey |
151 | | * * nNew |
152 | | * * nTried |
153 | | * * number of "new" buckets XOR 2**30 |
154 | | * * all new addresses (total count: nNew) |
155 | | * * all tried addresses (total count: nTried) |
156 | | * * for each new bucket: |
157 | | * * number of elements |
158 | | * * for each element: index in the serialized "all new addresses" |
159 | | * * asmap checksum |
160 | | * |
161 | | * 2**30 is xorred with the number of buckets to make addrman deserializer v0 detect it |
162 | | * as incompatible. This is necessary because it did not check the version number on |
163 | | * deserialization. |
164 | | * |
165 | | * vvNew, vvTried, mapInfo, mapAddr and vRandom are never encoded explicitly; |
166 | | * they are instead reconstructed from the other information. |
167 | | * |
168 | | * This format is more complex, but significantly smaller (at most 1.5 MiB), and supports |
169 | | * changes to the ADDRMAN_ parameters without breaking the on-disk structure. |
170 | | * |
171 | | * We don't use SERIALIZE_METHODS since the serialization and deserialization code has |
172 | | * very little in common. |
173 | | */ |
174 | | |
175 | | // Always serialize in the latest version (FILE_FORMAT). |
176 | 0 | ParamsStream s{s_, CAddress::V2_DISK}; |
177 | |
|
178 | 0 | s << static_cast<uint8_t>(FILE_FORMAT); |
179 | | |
180 | | // Increment `lowest_compatible` iff a newly introduced format is incompatible with |
181 | | // the previous one. |
182 | 0 | static constexpr uint8_t lowest_compatible = Format::V4_MULTIPORT; |
183 | 0 | s << static_cast<uint8_t>(INCOMPATIBILITY_BASE + lowest_compatible); |
184 | |
|
185 | 0 | s << nKey; |
186 | 0 | s << nNew; |
187 | 0 | s << nTried; |
188 | |
|
189 | 0 | int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30); |
190 | 0 | s << nUBuckets; |
191 | 0 | std::unordered_map<int, int> mapUnkIds; |
192 | 0 | int nIds = 0; |
193 | 0 | for (const auto& entry : mapInfo) { Branch (193:28): [True: 0, False: 0]
Branch (193:28): [True: 0, False: 0]
|
194 | 0 | mapUnkIds[entry.first] = nIds; |
195 | 0 | const AddrInfo& info = entry.second; |
196 | 0 | if (info.nRefCount) { Branch (196:13): [True: 0, False: 0]
Branch (196:13): [True: 0, False: 0]
|
197 | 0 | assert(nIds != nNew); // this means nNew was wrong, oh ow |
198 | 0 | s << info; |
199 | 0 | nIds++; |
200 | 0 | } |
201 | 0 | } |
202 | 0 | nIds = 0; |
203 | 0 | for (const auto& entry : mapInfo) { Branch (203:28): [True: 0, False: 0]
Branch (203:28): [True: 0, False: 0]
|
204 | 0 | const AddrInfo& info = entry.second; |
205 | 0 | if (info.fInTried) { Branch (205:13): [True: 0, False: 0]
Branch (205:13): [True: 0, False: 0]
|
206 | 0 | assert(nIds != nTried); // this means nTried was wrong, oh ow |
207 | 0 | s << info; |
208 | 0 | nIds++; |
209 | 0 | } |
210 | 0 | } |
211 | 0 | for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) { Branch (211:26): [True: 0, False: 0]
Branch (211:26): [True: 0, False: 0]
|
212 | 0 | int nSize = 0; |
213 | 0 | for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) { Branch (213:25): [True: 0, False: 0]
Branch (213:25): [True: 0, False: 0]
|
214 | 0 | if (vvNew[bucket][i] != -1) Branch (214:17): [True: 0, False: 0]
Branch (214:17): [True: 0, False: 0]
|
215 | 0 | nSize++; |
216 | 0 | } |
217 | 0 | s << nSize; |
218 | 0 | for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) { Branch (218:25): [True: 0, False: 0]
Branch (218:25): [True: 0, False: 0]
|
219 | 0 | if (vvNew[bucket][i] != -1) { Branch (219:17): [True: 0, False: 0]
Branch (219:17): [True: 0, False: 0]
|
220 | 0 | int nIndex = mapUnkIds[vvNew[bucket][i]]; |
221 | 0 | s << nIndex; |
222 | 0 | } |
223 | 0 | } |
224 | 0 | } |
225 | | // Store asmap checksum after bucket entries so that it |
226 | | // can be ignored by older clients for backward compatibility. |
227 | 0 | s << m_netgroupman.GetAsmapChecksum(); |
228 | 0 | } Unexecuted instantiation: void AddrManImpl::Serialize<HashedSourceWriter<AutoFile> >(HashedSourceWriter<AutoFile>&) const Unexecuted instantiation: void AddrManImpl::Serialize<DataStream>(DataStream&) const |
229 | | |
230 | | template <typename Stream> |
231 | | void AddrManImpl::Unserialize(Stream& s_) |
232 | 0 | { |
233 | 0 | LOCK(cs); |
234 | |
|
235 | 0 | assert(vRandom.empty()); |
236 | | |
237 | 0 | Format format; |
238 | 0 | s_ >> Using<CustomUintFormatter<1>>(format); |
239 | |
|
240 | 0 | const auto ser_params = (format >= Format::V3_BIP155 ? CAddress::V2_DISK : CAddress::V1_DISK); Branch (240:30): [True: 0, False: 0]
Branch (240:30): [True: 0, False: 0]
Branch (240:30): [True: 0, False: 0]
Branch (240:30): [True: 0, False: 0]
|
241 | 0 | ParamsStream s{s_, ser_params}; |
242 | |
|
243 | 0 | uint8_t compat; |
244 | 0 | s >> compat; |
245 | 0 | if (compat < INCOMPATIBILITY_BASE) { Branch (245:9): [True: 0, False: 0]
Branch (245:9): [True: 0, False: 0]
Branch (245:9): [True: 0, False: 0]
Branch (245:9): [True: 0, False: 0]
|
246 | 0 | throw std::ios_base::failure(strprintf( |
247 | 0 | "Corrupted addrman database: The compat value (%u) " |
248 | 0 | "is lower than the expected minimum value %u.", |
249 | 0 | compat, INCOMPATIBILITY_BASE)); |
250 | 0 | } |
251 | 0 | const uint8_t lowest_compatible = compat - INCOMPATIBILITY_BASE; |
252 | 0 | if (lowest_compatible > FILE_FORMAT) { Branch (252:9): [True: 0, False: 0]
Branch (252:9): [True: 0, False: 0]
Branch (252:9): [True: 0, False: 0]
Branch (252:9): [True: 0, False: 0]
|
253 | 0 | throw InvalidAddrManVersionError(strprintf( |
254 | 0 | "Unsupported format of addrman database: %u. It is compatible with formats >=%u, " |
255 | 0 | "but the maximum supported by this version of %s is %u.", |
256 | 0 | uint8_t{format}, lowest_compatible, PACKAGE_NAME, uint8_t{FILE_FORMAT})); |
257 | 0 | } |
258 | | |
259 | 0 | s >> nKey; |
260 | 0 | s >> nNew; |
261 | 0 | s >> nTried; |
262 | 0 | int nUBuckets = 0; |
263 | 0 | s >> nUBuckets; |
264 | 0 | if (format >= Format::V1_DETERMINISTIC) { Branch (264:9): [True: 0, False: 0]
Branch (264:9): [True: 0, False: 0]
Branch (264:9): [True: 0, False: 0]
Branch (264:9): [True: 0, False: 0]
|
265 | 0 | nUBuckets ^= (1 << 30); |
266 | 0 | } |
267 | |
|
268 | 0 | if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nNew < 0) { Branch (268:9): [True: 0, False: 0]
Branch (268:66): [True: 0, False: 0]
Branch (268:9): [True: 0, False: 0]
Branch (268:66): [True: 0, False: 0]
Branch (268:9): [True: 0, False: 0]
Branch (268:66): [True: 0, False: 0]
Branch (268:9): [True: 0, False: 0]
Branch (268:66): [True: 0, False: 0]
|
269 | 0 | throw std::ios_base::failure( |
270 | 0 | strprintf("Corrupt AddrMan serialization: nNew=%d, should be in [0, %d]", |
271 | 0 | nNew, |
272 | 0 | ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE)); |
273 | 0 | } |
274 | | |
275 | 0 | if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nTried < 0) { Branch (275:9): [True: 0, False: 0]
Branch (275:70): [True: 0, False: 0]
Branch (275:9): [True: 0, False: 0]
Branch (275:70): [True: 0, False: 0]
Branch (275:9): [True: 0, False: 0]
Branch (275:70): [True: 0, False: 0]
Branch (275:9): [True: 0, False: 0]
Branch (275:70): [True: 0, False: 0]
|
276 | 0 | throw std::ios_base::failure( |
277 | 0 | strprintf("Corrupt AddrMan serialization: nTried=%d, should be in [0, %d]", |
278 | 0 | nTried, |
279 | 0 | ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE)); |
280 | 0 | } |
281 | | |
282 | | // Deserialize entries from the new table. |
283 | 0 | for (int n = 0; n < nNew; n++) { Branch (283:21): [True: 0, False: 0]
Branch (283:21): [True: 0, False: 0]
Branch (283:21): [True: 0, False: 0]
Branch (283:21): [True: 0, False: 0]
|
284 | 0 | AddrInfo& info = mapInfo[n]; |
285 | 0 | s >> info; |
286 | 0 | mapAddr[info] = n; |
287 | 0 | info.nRandomPos = vRandom.size(); |
288 | 0 | vRandom.push_back(n); |
289 | 0 | m_network_counts[info.GetNetwork()].n_new++; |
290 | 0 | } |
291 | 0 | nIdCount = nNew; |
292 | | |
293 | | // Deserialize entries from the tried table. |
294 | 0 | int nLost = 0; |
295 | 0 | for (int n = 0; n < nTried; n++) { Branch (295:21): [True: 0, False: 0]
Branch (295:21): [True: 0, False: 0]
Branch (295:21): [True: 0, False: 0]
Branch (295:21): [True: 0, False: 0]
|
296 | 0 | AddrInfo info; |
297 | 0 | s >> info; |
298 | 0 | int nKBucket = info.GetTriedBucket(nKey, m_netgroupman); |
299 | 0 | int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket); |
300 | 0 | if (info.IsValid() Branch (300:13): [True: 0, False: 0]
Branch (300:13): [True: 0, False: 0]
Branch (300:13): [True: 0, False: 0]
Branch (300:13): [True: 0, False: 0]
|
301 | 0 | && vvTried[nKBucket][nKBucketPos] == -1) { Branch (301:20): [True: 0, False: 0]
Branch (301:20): [True: 0, False: 0]
Branch (301:20): [True: 0, False: 0]
Branch (301:20): [True: 0, False: 0]
|
302 | 0 | info.nRandomPos = vRandom.size(); |
303 | 0 | info.fInTried = true; |
304 | 0 | vRandom.push_back(nIdCount); |
305 | 0 | mapInfo[nIdCount] = info; |
306 | 0 | mapAddr[info] = nIdCount; |
307 | 0 | vvTried[nKBucket][nKBucketPos] = nIdCount; |
308 | 0 | nIdCount++; |
309 | 0 | m_network_counts[info.GetNetwork()].n_tried++; |
310 | 0 | } else { |
311 | 0 | nLost++; |
312 | 0 | } |
313 | 0 | } |
314 | 0 | nTried -= nLost; |
315 | | |
316 | | // Store positions in the new table buckets to apply later (if possible). |
317 | | // An entry may appear in up to ADDRMAN_NEW_BUCKETS_PER_ADDRESS buckets, |
318 | | // so we store all bucket-entry_index pairs to iterate through later. |
319 | 0 | std::vector<std::pair<int, int>> bucket_entries; |
320 | |
|
321 | 0 | for (int bucket = 0; bucket < nUBuckets; ++bucket) { Branch (321:26): [True: 0, False: 0]
Branch (321:26): [True: 0, False: 0]
Branch (321:26): [True: 0, False: 0]
Branch (321:26): [True: 0, False: 0]
|
322 | 0 | int num_entries{0}; |
323 | 0 | s >> num_entries; |
324 | 0 | for (int n = 0; n < num_entries; ++n) { Branch (324:25): [True: 0, False: 0]
Branch (324:25): [True: 0, False: 0]
Branch (324:25): [True: 0, False: 0]
Branch (324:25): [True: 0, False: 0]
|
325 | 0 | int entry_index{0}; |
326 | 0 | s >> entry_index; |
327 | 0 | if (entry_index >= 0 && entry_index < nNew) { Branch (327:17): [True: 0, False: 0]
Branch (327:37): [True: 0, False: 0]
Branch (327:17): [True: 0, False: 0]
Branch (327:37): [True: 0, False: 0]
Branch (327:17): [True: 0, False: 0]
Branch (327:37): [True: 0, False: 0]
Branch (327:17): [True: 0, False: 0]
Branch (327:37): [True: 0, False: 0]
|
328 | 0 | bucket_entries.emplace_back(bucket, entry_index); |
329 | 0 | } |
330 | 0 | } |
331 | 0 | } |
332 | | |
333 | | // If the bucket count and asmap checksum haven't changed, then attempt |
334 | | // to restore the entries to the buckets/positions they were in before |
335 | | // serialization. |
336 | 0 | uint256 supplied_asmap_checksum{m_netgroupman.GetAsmapChecksum()}; |
337 | 0 | uint256 serialized_asmap_checksum; |
338 | 0 | if (format >= Format::V2_ASMAP) { Branch (338:9): [True: 0, False: 0]
Branch (338:9): [True: 0, False: 0]
Branch (338:9): [True: 0, False: 0]
Branch (338:9): [True: 0, False: 0]
|
339 | 0 | s >> serialized_asmap_checksum; |
340 | 0 | } |
341 | 0 | const bool restore_bucketing{nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && Branch (341:34): [True: 0, False: 0]
Branch (341:34): [True: 0, False: 0]
Branch (341:34): [True: 0, False: 0]
Branch (341:34): [True: 0, False: 0]
|
342 | 0 | serialized_asmap_checksum == supplied_asmap_checksum}; Branch (342:9): [True: 0, False: 0]
Branch (342:9): [True: 0, False: 0]
Branch (342:9): [True: 0, False: 0]
Branch (342:9): [True: 0, False: 0]
|
343 | |
|
344 | 0 | if (!restore_bucketing) { Branch (344:9): [True: 0, False: 0]
Branch (344:9): [True: 0, False: 0]
Branch (344:9): [True: 0, False: 0]
Branch (344:9): [True: 0, False: 0]
|
345 | 0 | LogPrint(BCLog::ADDRMAN, "Bucketing method was updated, re-bucketing addrman entries from disk\n"); |
346 | 0 | } |
347 | |
|
348 | 0 | for (auto bucket_entry : bucket_entries) { Branch (348:28): [True: 0, False: 0]
Branch (348:28): [True: 0, False: 0]
Branch (348:28): [True: 0, False: 0]
Branch (348:28): [True: 0, False: 0]
|
349 | 0 | int bucket{bucket_entry.first}; |
350 | 0 | const int entry_index{bucket_entry.second}; |
351 | 0 | AddrInfo& info = mapInfo[entry_index]; |
352 | | |
353 | | // Don't store the entry in the new bucket if it's not a valid address for our addrman |
354 | 0 | if (!info.IsValid()) continue; Branch (354:13): [True: 0, False: 0]
Branch (354:13): [True: 0, False: 0]
Branch (354:13): [True: 0, False: 0]
Branch (354:13): [True: 0, False: 0]
|
355 | | |
356 | | // The entry shouldn't appear in more than |
357 | | // ADDRMAN_NEW_BUCKETS_PER_ADDRESS. If it has already, just skip |
358 | | // this bucket_entry. |
359 | 0 | if (info.nRefCount >= ADDRMAN_NEW_BUCKETS_PER_ADDRESS) continue; Branch (359:13): [True: 0, False: 0]
Branch (359:13): [True: 0, False: 0]
Branch (359:13): [True: 0, False: 0]
Branch (359:13): [True: 0, False: 0]
|
360 | | |
361 | 0 | int bucket_position = info.GetBucketPosition(nKey, true, bucket); |
362 | 0 | if (restore_bucketing && vvNew[bucket][bucket_position] == -1) { Branch (362:13): [True: 0, False: 0]
Branch (362:34): [True: 0, False: 0]
Branch (362:13): [True: 0, False: 0]
Branch (362:34): [True: 0, False: 0]
Branch (362:13): [True: 0, False: 0]
Branch (362:34): [True: 0, False: 0]
Branch (362:13): [True: 0, False: 0]
Branch (362:34): [True: 0, False: 0]
|
363 | | // Bucketing has not changed, using existing bucket positions for the new table |
364 | 0 | vvNew[bucket][bucket_position] = entry_index; |
365 | 0 | ++info.nRefCount; |
366 | 0 | } else { |
367 | | // In case the new table data cannot be used (bucket count wrong or new asmap), |
368 | | // try to give them a reference based on their primary source address. |
369 | 0 | bucket = info.GetNewBucket(nKey, m_netgroupman); |
370 | 0 | bucket_position = info.GetBucketPosition(nKey, true, bucket); |
371 | 0 | if (vvNew[bucket][bucket_position] == -1) { Branch (371:17): [True: 0, False: 0]
Branch (371:17): [True: 0, False: 0]
Branch (371:17): [True: 0, False: 0]
Branch (371:17): [True: 0, False: 0]
|
372 | 0 | vvNew[bucket][bucket_position] = entry_index; |
373 | 0 | ++info.nRefCount; |
374 | 0 | } |
375 | 0 | } |
376 | 0 | } |
377 | | |
378 | | // Prune new entries with refcount 0 (as a result of collisions or invalid address). |
379 | 0 | int nLostUnk = 0; |
380 | 0 | for (auto it = mapInfo.cbegin(); it != mapInfo.cend(); ) { Branch (380:38): [True: 0, False: 0]
Branch (380:38): [True: 0, False: 0]
Branch (380:38): [True: 0, False: 0]
Branch (380:38): [True: 0, False: 0]
|
381 | 0 | if (it->second.fInTried == false && it->second.nRefCount == 0) { Branch (381:13): [True: 0, False: 0]
Branch (381:45): [True: 0, False: 0]
Branch (381:13): [True: 0, False: 0]
Branch (381:45): [True: 0, False: 0]
Branch (381:13): [True: 0, False: 0]
Branch (381:45): [True: 0, False: 0]
Branch (381:13): [True: 0, False: 0]
Branch (381:45): [True: 0, False: 0]
|
382 | 0 | const auto itCopy = it++; |
383 | 0 | Delete(itCopy->first); |
384 | 0 | ++nLostUnk; |
385 | 0 | } else { |
386 | 0 | ++it; |
387 | 0 | } |
388 | 0 | } |
389 | 0 | if (nLost + nLostUnk > 0) { Branch (389:9): [True: 0, False: 0]
Branch (389:9): [True: 0, False: 0]
Branch (389:9): [True: 0, False: 0]
Branch (389:9): [True: 0, False: 0]
|
390 | 0 | LogPrint(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions or invalid addresses\n", nLostUnk, nLost); |
391 | 0 | } |
392 | |
|
393 | 0 | const int check_code{CheckAddrman()}; |
394 | 0 | if (check_code != 0) { Branch (394:9): [True: 0, False: 0]
Branch (394:9): [True: 0, False: 0]
Branch (394:9): [True: 0, False: 0]
Branch (394:9): [True: 0, False: 0]
|
395 | 0 | throw std::ios_base::failure(strprintf( |
396 | 0 | "Corrupt data. Consistency check failed with code %s", |
397 | 0 | check_code)); |
398 | 0 | } |
399 | 0 | } Unexecuted instantiation: void AddrManImpl::Unserialize<AutoFile>(AutoFile&) Unexecuted instantiation: void AddrManImpl::Unserialize<HashVerifier<AutoFile> >(HashVerifier<AutoFile>&) Unexecuted instantiation: void AddrManImpl::Unserialize<DataStream>(DataStream&) Unexecuted instantiation: void AddrManImpl::Unserialize<HashVerifier<DataStream> >(HashVerifier<DataStream>&) |
400 | | |
401 | | AddrInfo* AddrManImpl::Find(const CService& addr, int* pnId) |
402 | 1.45k | { |
403 | 1.45k | AssertLockHeld(cs); |
404 | | |
405 | 1.45k | const auto it = mapAddr.find(addr); |
406 | 1.45k | if (it == mapAddr.end()) Branch (406:9): [True: 1.45k, False: 0]
|
407 | 1.45k | return nullptr; |
408 | 0 | if (pnId) Branch (408:9): [True: 0, False: 0]
|
409 | 0 | *pnId = (*it).second; |
410 | 0 | const auto it2 = mapInfo.find((*it).second); |
411 | 0 | if (it2 != mapInfo.end()) Branch (411:9): [True: 0, False: 0]
|
412 | 0 | return &(*it2).second; |
413 | 0 | return nullptr; |
414 | 0 | } |
415 | | |
416 | | AddrInfo* AddrManImpl::Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId) |
417 | 0 | { |
418 | 0 | AssertLockHeld(cs); |
419 | |
|
420 | 0 | int nId = nIdCount++; |
421 | 0 | mapInfo[nId] = AddrInfo(addr, addrSource); |
422 | 0 | mapAddr[addr] = nId; |
423 | 0 | mapInfo[nId].nRandomPos = vRandom.size(); |
424 | 0 | vRandom.push_back(nId); |
425 | 0 | nNew++; |
426 | 0 | m_network_counts[addr.GetNetwork()].n_new++; |
427 | 0 | if (pnId) Branch (427:9): [True: 0, False: 0]
|
428 | 0 | *pnId = nId; |
429 | 0 | return &mapInfo[nId]; |
430 | 0 | } |
431 | | |
432 | | void AddrManImpl::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2) const |
433 | 0 | { |
434 | 0 | AssertLockHeld(cs); |
435 | |
|
436 | 0 | if (nRndPos1 == nRndPos2) Branch (436:9): [True: 0, False: 0]
|
437 | 0 | return; |
438 | | |
439 | 0 | assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size()); |
440 | | |
441 | 0 | int nId1 = vRandom[nRndPos1]; |
442 | 0 | int nId2 = vRandom[nRndPos2]; |
443 | |
|
444 | 0 | const auto it_1{mapInfo.find(nId1)}; |
445 | 0 | const auto it_2{mapInfo.find(nId2)}; |
446 | 0 | assert(it_1 != mapInfo.end()); |
447 | 0 | assert(it_2 != mapInfo.end()); |
448 | | |
449 | 0 | it_1->second.nRandomPos = nRndPos2; |
450 | 0 | it_2->second.nRandomPos = nRndPos1; |
451 | |
|
452 | 0 | vRandom[nRndPos1] = nId2; |
453 | 0 | vRandom[nRndPos2] = nId1; |
454 | 0 | } |
455 | | |
456 | | void AddrManImpl::Delete(int nId) |
457 | 0 | { |
458 | 0 | AssertLockHeld(cs); |
459 | |
|
460 | 0 | assert(mapInfo.count(nId) != 0); |
461 | 0 | AddrInfo& info = mapInfo[nId]; |
462 | 0 | assert(!info.fInTried); |
463 | 0 | assert(info.nRefCount == 0); |
464 | | |
465 | 0 | SwapRandom(info.nRandomPos, vRandom.size() - 1); |
466 | 0 | m_network_counts[info.GetNetwork()].n_new--; |
467 | 0 | vRandom.pop_back(); |
468 | 0 | mapAddr.erase(info); |
469 | 0 | mapInfo.erase(nId); |
470 | 0 | nNew--; |
471 | 0 | } |
472 | | |
473 | | void AddrManImpl::ClearNew(int nUBucket, int nUBucketPos) |
474 | 0 | { |
475 | 0 | AssertLockHeld(cs); |
476 | | |
477 | | // if there is an entry in the specified bucket, delete it. |
478 | 0 | if (vvNew[nUBucket][nUBucketPos] != -1) { Branch (478:9): [True: 0, False: 0]
|
479 | 0 | int nIdDelete = vvNew[nUBucket][nUBucketPos]; |
480 | 0 | AddrInfo& infoDelete = mapInfo[nIdDelete]; |
481 | 0 | assert(infoDelete.nRefCount > 0); |
482 | 0 | infoDelete.nRefCount--; |
483 | 0 | vvNew[nUBucket][nUBucketPos] = -1; |
484 | 0 | LogPrint(BCLog::ADDRMAN, "Removed %s from new[%i][%i]\n", infoDelete.ToStringAddrPort(), nUBucket, nUBucketPos); |
485 | 0 | if (infoDelete.nRefCount == 0) { Branch (485:13): [True: 0, False: 0]
|
486 | 0 | Delete(nIdDelete); |
487 | 0 | } |
488 | 0 | } |
489 | 0 | } |
490 | | |
491 | | void AddrManImpl::MakeTried(AddrInfo& info, int nId) |
492 | 0 | { |
493 | 0 | AssertLockHeld(cs); |
494 | | |
495 | | // remove the entry from all new buckets |
496 | 0 | const int start_bucket{info.GetNewBucket(nKey, m_netgroupman)}; |
497 | 0 | for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; ++n) { Branch (497:21): [True: 0, False: 0]
|
498 | 0 | const int bucket{(start_bucket + n) % ADDRMAN_NEW_BUCKET_COUNT}; |
499 | 0 | const int pos{info.GetBucketPosition(nKey, true, bucket)}; |
500 | 0 | if (vvNew[bucket][pos] == nId) { Branch (500:13): [True: 0, False: 0]
|
501 | 0 | vvNew[bucket][pos] = -1; |
502 | 0 | info.nRefCount--; |
503 | 0 | if (info.nRefCount == 0) break; Branch (503:17): [True: 0, False: 0]
|
504 | 0 | } |
505 | 0 | } |
506 | 0 | nNew--; |
507 | 0 | m_network_counts[info.GetNetwork()].n_new--; |
508 | |
|
509 | 0 | assert(info.nRefCount == 0); |
510 | | |
511 | | // which tried bucket to move the entry to |
512 | 0 | int nKBucket = info.GetTriedBucket(nKey, m_netgroupman); |
513 | 0 | int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket); |
514 | | |
515 | | // first make space to add it (the existing tried entry there is moved to new, deleting whatever is there). |
516 | 0 | if (vvTried[nKBucket][nKBucketPos] != -1) { Branch (516:9): [True: 0, False: 0]
|
517 | | // find an item to evict |
518 | 0 | int nIdEvict = vvTried[nKBucket][nKBucketPos]; |
519 | 0 | assert(mapInfo.count(nIdEvict) == 1); |
520 | 0 | AddrInfo& infoOld = mapInfo[nIdEvict]; |
521 | | |
522 | | // Remove the to-be-evicted item from the tried set. |
523 | 0 | infoOld.fInTried = false; |
524 | 0 | vvTried[nKBucket][nKBucketPos] = -1; |
525 | 0 | nTried--; |
526 | 0 | m_network_counts[infoOld.GetNetwork()].n_tried--; |
527 | | |
528 | | // find which new bucket it belongs to |
529 | 0 | int nUBucket = infoOld.GetNewBucket(nKey, m_netgroupman); |
530 | 0 | int nUBucketPos = infoOld.GetBucketPosition(nKey, true, nUBucket); |
531 | 0 | ClearNew(nUBucket, nUBucketPos); |
532 | 0 | assert(vvNew[nUBucket][nUBucketPos] == -1); |
533 | | |
534 | | // Enter it into the new set again. |
535 | 0 | infoOld.nRefCount = 1; |
536 | 0 | vvNew[nUBucket][nUBucketPos] = nIdEvict; |
537 | 0 | nNew++; |
538 | 0 | m_network_counts[infoOld.GetNetwork()].n_new++; |
539 | 0 | LogPrint(BCLog::ADDRMAN, "Moved %s from tried[%i][%i] to new[%i][%i] to make space\n", |
540 | 0 | infoOld.ToStringAddrPort(), nKBucket, nKBucketPos, nUBucket, nUBucketPos); |
541 | 0 | } |
542 | 0 | assert(vvTried[nKBucket][nKBucketPos] == -1); |
543 | | |
544 | 0 | vvTried[nKBucket][nKBucketPos] = nId; |
545 | 0 | nTried++; |
546 | 0 | info.fInTried = true; |
547 | 0 | m_network_counts[info.GetNetwork()].n_tried++; |
548 | 0 | } |
549 | | |
550 | | bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, std::chrono::seconds time_penalty) |
551 | 0 | { |
552 | 0 | AssertLockHeld(cs); |
553 | |
|
554 | 0 | if (!addr.IsRoutable()) Branch (554:9): [True: 0, False: 0]
|
555 | 0 | return false; |
556 | | |
557 | 0 | int nId; |
558 | 0 | AddrInfo* pinfo = Find(addr, &nId); |
559 | | |
560 | | // Do not set a penalty for a source's self-announcement |
561 | 0 | if (addr == source) { Branch (561:9): [True: 0, False: 0]
|
562 | 0 | time_penalty = 0s; |
563 | 0 | } |
564 | |
|
565 | 0 | if (pinfo) { Branch (565:9): [True: 0, False: 0]
|
566 | | // periodically update nTime |
567 | 0 | const bool currently_online{NodeClock::now() - addr.nTime < 24h}; |
568 | 0 | const auto update_interval{currently_online ? 1h : 24h}; Branch (568:36): [True: 0, False: 0]
|
569 | 0 | if (pinfo->nTime < addr.nTime - update_interval - time_penalty) { Branch (569:13): [True: 0, False: 0]
|
570 | 0 | pinfo->nTime = std::max(NodeSeconds{0s}, addr.nTime - time_penalty); |
571 | 0 | } |
572 | | |
573 | | // add services |
574 | 0 | pinfo->nServices = ServiceFlags(pinfo->nServices | addr.nServices); |
575 | | |
576 | | // do not update if no new information is present |
577 | 0 | if (addr.nTime <= pinfo->nTime) { Branch (577:13): [True: 0, False: 0]
|
578 | 0 | return false; |
579 | 0 | } |
580 | | |
581 | | // do not update if the entry was already in the "tried" table |
582 | 0 | if (pinfo->fInTried) Branch (582:13): [True: 0, False: 0]
|
583 | 0 | return false; |
584 | | |
585 | | // do not update if the max reference count is reached |
586 | 0 | if (pinfo->nRefCount == ADDRMAN_NEW_BUCKETS_PER_ADDRESS) Branch (586:13): [True: 0, False: 0]
|
587 | 0 | return false; |
588 | | |
589 | | // stochastic test: previous nRefCount == N: 2^N times harder to increase it |
590 | 0 | if (pinfo->nRefCount > 0) { Branch (590:13): [True: 0, False: 0]
|
591 | 0 | const int nFactor{1 << pinfo->nRefCount}; |
592 | 0 | if (insecure_rand.randrange(nFactor) != 0) return false; Branch (592:17): [True: 0, False: 0]
|
593 | 0 | } |
594 | 0 | } else { |
595 | 0 | pinfo = Create(addr, source, &nId); |
596 | 0 | pinfo->nTime = std::max(NodeSeconds{0s}, pinfo->nTime - time_penalty); |
597 | 0 | } |
598 | | |
599 | 0 | int nUBucket = pinfo->GetNewBucket(nKey, source, m_netgroupman); |
600 | 0 | int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket); |
601 | 0 | bool fInsert = vvNew[nUBucket][nUBucketPos] == -1; |
602 | 0 | if (vvNew[nUBucket][nUBucketPos] != nId) { Branch (602:9): [True: 0, False: 0]
|
603 | 0 | if (!fInsert) { Branch (603:13): [True: 0, False: 0]
|
604 | 0 | AddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]]; |
605 | 0 | if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) { Branch (605:17): [True: 0, False: 0]
Branch (605:47): [True: 0, False: 0]
Branch (605:77): [True: 0, False: 0]
|
606 | | // Overwrite the existing new table entry. |
607 | 0 | fInsert = true; |
608 | 0 | } |
609 | 0 | } |
610 | 0 | if (fInsert) { Branch (610:13): [True: 0, False: 0]
|
611 | 0 | ClearNew(nUBucket, nUBucketPos); |
612 | 0 | pinfo->nRefCount++; |
613 | 0 | vvNew[nUBucket][nUBucketPos] = nId; |
614 | 0 | const auto mapped_as{m_netgroupman.GetMappedAS(addr)}; |
615 | 0 | LogPrint(BCLog::ADDRMAN, "Added %s%s to new[%i][%i]\n", |
616 | 0 | addr.ToStringAddrPort(), (mapped_as ? strprintf(" mapped to AS%i", mapped_as) : ""), nUBucket, nUBucketPos); |
617 | 0 | } else { |
618 | 0 | if (pinfo->nRefCount == 0) { Branch (618:17): [True: 0, False: 0]
|
619 | 0 | Delete(nId); |
620 | 0 | } |
621 | 0 | } |
622 | 0 | } |
623 | 0 | return fInsert; |
624 | 0 | } |
625 | | |
626 | | bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, NodeSeconds time) |
627 | 580 | { |
628 | 580 | AssertLockHeld(cs); |
629 | | |
630 | 580 | int nId; |
631 | | |
632 | 580 | m_last_good = time; |
633 | | |
634 | 580 | AddrInfo* pinfo = Find(addr, &nId); |
635 | | |
636 | | // if not found, bail out |
637 | 580 | if (!pinfo) return false; Branch (637:9): [True: 580, False: 0]
|
638 | | |
639 | 0 | AddrInfo& info = *pinfo; |
640 | | |
641 | | // update info |
642 | 0 | info.m_last_success = time; |
643 | 0 | info.m_last_try = time; |
644 | 0 | info.nAttempts = 0; |
645 | | // nTime is not updated here, to avoid leaking information about |
646 | | // currently-connected peers. |
647 | | |
648 | | // if it is already in the tried set, don't do anything else |
649 | 0 | if (info.fInTried) return false; Branch (649:9): [True: 0, False: 0]
|
650 | | |
651 | | // if it is not in new, something bad happened |
652 | 0 | if (!Assume(info.nRefCount > 0)) return false; Branch (652:9): [True: 0, False: 0]
|
653 | | |
654 | | |
655 | | // which tried bucket to move the entry to |
656 | 0 | int tried_bucket = info.GetTriedBucket(nKey, m_netgroupman); |
657 | 0 | int tried_bucket_pos = info.GetBucketPosition(nKey, false, tried_bucket); |
658 | | |
659 | | // Will moving this address into tried evict another entry? |
660 | 0 | if (test_before_evict && (vvTried[tried_bucket][tried_bucket_pos] != -1)) { Branch (660:9): [True: 0, False: 0]
Branch (660:30): [True: 0, False: 0]
|
661 | 0 | if (m_tried_collisions.size() < ADDRMAN_SET_TRIED_COLLISION_SIZE) { Branch (661:13): [True: 0, False: 0]
|
662 | 0 | m_tried_collisions.insert(nId); |
663 | 0 | } |
664 | | // Output the entry we'd be colliding with, for debugging purposes |
665 | 0 | auto colliding_entry = mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]); |
666 | 0 | LogPrint(BCLog::ADDRMAN, "Collision with %s while attempting to move %s to tried table. Collisions=%d\n", |
667 | 0 | colliding_entry != mapInfo.end() ? colliding_entry->second.ToStringAddrPort() : "", |
668 | 0 | addr.ToStringAddrPort(), |
669 | 0 | m_tried_collisions.size()); |
670 | 0 | return false; |
671 | 0 | } else { |
672 | | // move nId to the tried tables |
673 | 0 | MakeTried(info, nId); |
674 | 0 | const auto mapped_as{m_netgroupman.GetMappedAS(addr)}; |
675 | 0 | LogPrint(BCLog::ADDRMAN, "Moved %s%s to tried[%i][%i]\n", |
676 | 0 | addr.ToStringAddrPort(), (mapped_as ? strprintf(" mapped to AS%i", mapped_as) : ""), tried_bucket, tried_bucket_pos); |
677 | 0 | return true; |
678 | 0 | } |
679 | 0 | } |
680 | | |
681 | | bool AddrManImpl::Add_(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty) |
682 | 0 | { |
683 | 0 | int added{0}; |
684 | 0 | for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++) { Branch (684:68): [True: 0, False: 0]
|
685 | 0 | added += AddSingle(*it, source, time_penalty) ? 1 : 0; Branch (685:18): [True: 0, False: 0]
|
686 | 0 | } |
687 | 0 | if (added > 0) { Branch (687:9): [True: 0, False: 0]
|
688 | 0 | LogPrint(BCLog::ADDRMAN, "Added %i addresses (of %i) from %s: %i tried, %i new\n", added, vAddr.size(), source.ToStringAddr(), nTried, nNew); |
689 | 0 | } |
690 | 0 | return added > 0; |
691 | 0 | } |
692 | | |
693 | | void AddrManImpl::Attempt_(const CService& addr, bool fCountFailure, NodeSeconds time) |
694 | 0 | { |
695 | 0 | AssertLockHeld(cs); |
696 | |
|
697 | 0 | AddrInfo* pinfo = Find(addr); |
698 | | |
699 | | // if not found, bail out |
700 | 0 | if (!pinfo) Branch (700:9): [True: 0, False: 0]
|
701 | 0 | return; |
702 | | |
703 | 0 | AddrInfo& info = *pinfo; |
704 | | |
705 | | // update info |
706 | 0 | info.m_last_try = time; |
707 | 0 | if (fCountFailure && info.m_last_count_attempt < m_last_good) { Branch (707:9): [True: 0, False: 0]
Branch (707:26): [True: 0, False: 0]
|
708 | 0 | info.m_last_count_attempt = time; |
709 | 0 | info.nAttempts++; |
710 | 0 | } |
711 | 0 | } |
712 | | |
713 | | std::pair<CAddress, NodeSeconds> AddrManImpl::Select_(bool new_only, std::optional<Network> network) const |
714 | 0 | { |
715 | 0 | AssertLockHeld(cs); |
716 | |
|
717 | 0 | if (vRandom.empty()) return {}; Branch (717:9): [True: 0, False: 0]
|
718 | | |
719 | 0 | size_t new_count = nNew; |
720 | 0 | size_t tried_count = nTried; |
721 | |
|
722 | 0 | if (network.has_value()) { Branch (722:9): [True: 0, False: 0]
|
723 | 0 | auto it = m_network_counts.find(*network); |
724 | 0 | if (it == m_network_counts.end()) return {}; Branch (724:13): [True: 0, False: 0]
|
725 | | |
726 | 0 | auto counts = it->second; |
727 | 0 | new_count = counts.n_new; |
728 | 0 | tried_count = counts.n_tried; |
729 | 0 | } |
730 | | |
731 | 0 | if (new_only && new_count == 0) return {}; Branch (731:9): [True: 0, False: 0]
Branch (731:21): [True: 0, False: 0]
|
732 | 0 | if (new_count + tried_count == 0) return {}; Branch (732:9): [True: 0, False: 0]
|
733 | | |
734 | | // Decide if we are going to search the new or tried table |
735 | | // If either option is viable, use a 50% chance to choose |
736 | 0 | bool search_tried; |
737 | 0 | if (new_only || tried_count == 0) { Branch (737:9): [True: 0, False: 0]
Branch (737:21): [True: 0, False: 0]
|
738 | 0 | search_tried = false; |
739 | 0 | } else if (new_count == 0) { Branch (739:16): [True: 0, False: 0]
|
740 | 0 | search_tried = true; |
741 | 0 | } else { |
742 | 0 | search_tried = insecure_rand.randbool(); |
743 | 0 | } |
744 | |
|
745 | 0 | const int bucket_count{search_tried ? ADDRMAN_TRIED_BUCKET_COUNT : ADDRMAN_NEW_BUCKET_COUNT}; Branch (745:28): [True: 0, False: 0]
|
746 | | |
747 | | // Loop through the addrman table until we find an appropriate entry |
748 | 0 | double chance_factor = 1.0; |
749 | 0 | while (1) { Branch (749:12): [Folded - Ignored]
|
750 | | // Pick a bucket, and an initial position in that bucket. |
751 | 0 | int bucket = insecure_rand.randrange(bucket_count); |
752 | 0 | int initial_position = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE); |
753 | | |
754 | | // Iterate over the positions of that bucket, starting at the initial one, |
755 | | // and looping around. |
756 | 0 | int i, position, node_id; |
757 | 0 | for (i = 0; i < ADDRMAN_BUCKET_SIZE; ++i) { Branch (757:21): [True: 0, False: 0]
|
758 | 0 | position = (initial_position + i) % ADDRMAN_BUCKET_SIZE; |
759 | 0 | node_id = GetEntry(search_tried, bucket, position); |
760 | 0 | if (node_id != -1) { Branch (760:17): [True: 0, False: 0]
|
761 | 0 | if (network.has_value()) { Branch (761:21): [True: 0, False: 0]
|
762 | 0 | const auto it{mapInfo.find(node_id)}; |
763 | 0 | if (Assume(it != mapInfo.end()) && it->second.GetNetwork() == *network) break; Branch (763:25): [True: 0, False: 0]
Branch (763:56): [True: 0, False: 0]
|
764 | 0 | } else { |
765 | 0 | break; |
766 | 0 | } |
767 | 0 | } |
768 | 0 | } |
769 | | |
770 | | // If the bucket is entirely empty, start over with a (likely) different one. |
771 | 0 | if (i == ADDRMAN_BUCKET_SIZE) continue; Branch (771:13): [True: 0, False: 0]
|
772 | | |
773 | | // Find the entry to return. |
774 | 0 | const auto it_found{mapInfo.find(node_id)}; |
775 | 0 | assert(it_found != mapInfo.end()); |
776 | 0 | const AddrInfo& info{it_found->second}; |
777 | | |
778 | | // With probability GetChance() * chance_factor, return the entry. |
779 | 0 | if (insecure_rand.randbits<30>() < chance_factor * info.GetChance() * (1 << 30)) { Branch (779:13): [True: 0, False: 0]
|
780 | 0 | LogPrint(BCLog::ADDRMAN, "Selected %s from %s\n", info.ToStringAddrPort(), search_tried ? "tried" : "new"); |
781 | 0 | return {info, info.m_last_try}; |
782 | 0 | } |
783 | | |
784 | | // Otherwise start over with a (likely) different bucket, and increased chance factor. |
785 | 0 | chance_factor *= 1.2; |
786 | 0 | } |
787 | 0 | } |
788 | | |
789 | | int AddrManImpl::GetEntry(bool use_tried, size_t bucket, size_t position) const |
790 | 0 | { |
791 | 0 | AssertLockHeld(cs); |
792 | |
|
793 | 0 | if (use_tried) { Branch (793:9): [True: 0, False: 0]
|
794 | 0 | if (Assume(position < ADDRMAN_BUCKET_SIZE) && Assume(bucket < ADDRMAN_TRIED_BUCKET_COUNT)) { Branch (794:13): [True: 0, False: 0]
|
795 | 0 | return vvTried[bucket][position]; |
796 | 0 | } |
797 | 0 | } else { |
798 | 0 | if (Assume(position < ADDRMAN_BUCKET_SIZE) && Assume(bucket < ADDRMAN_NEW_BUCKET_COUNT)) { Branch (798:13): [True: 0, False: 0]
|
799 | 0 | return vvNew[bucket][position]; |
800 | 0 | } |
801 | 0 | } |
802 | | |
803 | 0 | return -1; |
804 | 0 | } |
805 | | |
806 | | std::vector<CAddress> AddrManImpl::GetAddr_(size_t max_addresses, size_t max_pct, std::optional<Network> network, const bool filtered) const |
807 | 0 | { |
808 | 0 | AssertLockHeld(cs); |
809 | |
|
810 | 0 | size_t nNodes = vRandom.size(); |
811 | 0 | if (max_pct != 0) { Branch (811:9): [True: 0, False: 0]
|
812 | 0 | nNodes = max_pct * nNodes / 100; |
813 | 0 | } |
814 | 0 | if (max_addresses != 0) { Branch (814:9): [True: 0, False: 0]
|
815 | 0 | nNodes = std::min(nNodes, max_addresses); |
816 | 0 | } |
817 | | |
818 | | // gather a list of random nodes, skipping those of low quality |
819 | 0 | const auto now{Now<NodeSeconds>()}; |
820 | 0 | std::vector<CAddress> addresses; |
821 | 0 | for (unsigned int n = 0; n < vRandom.size(); n++) { Branch (821:30): [True: 0, False: 0]
|
822 | 0 | if (addresses.size() >= nNodes) Branch (822:13): [True: 0, False: 0]
|
823 | 0 | break; |
824 | | |
825 | 0 | int nRndPos = insecure_rand.randrange(vRandom.size() - n) + n; |
826 | 0 | SwapRandom(n, nRndPos); |
827 | 0 | const auto it{mapInfo.find(vRandom[n])}; |
828 | 0 | assert(it != mapInfo.end()); |
829 | | |
830 | 0 | const AddrInfo& ai{it->second}; |
831 | | |
832 | | // Filter by network (optional) |
833 | 0 | if (network != std::nullopt && ai.GetNetClass() != network) continue; Branch (833:13): [True: 0, False: 0]
Branch (833:13): [True: 0, False: 0]
Branch (833:40): [True: 0, False: 0]
|
834 | | |
835 | | // Filter for quality |
836 | 0 | if (ai.IsTerrible(now) && filtered) continue; Branch (836:13): [True: 0, False: 0]
Branch (836:35): [True: 0, False: 0]
|
837 | | |
838 | 0 | addresses.push_back(ai); |
839 | 0 | } |
840 | 0 | LogPrint(BCLog::ADDRMAN, "GetAddr returned %d random addresses\n", addresses.size()); |
841 | 0 | return addresses; |
842 | 0 | } |
843 | | |
844 | | std::vector<std::pair<AddrInfo, AddressPosition>> AddrManImpl::GetEntries_(bool from_tried) const |
845 | 0 | { |
846 | 0 | AssertLockHeld(cs); |
847 | |
|
848 | 0 | const int bucket_count = from_tried ? ADDRMAN_TRIED_BUCKET_COUNT : ADDRMAN_NEW_BUCKET_COUNT; Branch (848:30): [True: 0, False: 0]
|
849 | 0 | std::vector<std::pair<AddrInfo, AddressPosition>> infos; |
850 | 0 | for (int bucket = 0; bucket < bucket_count; ++bucket) { Branch (850:26): [True: 0, False: 0]
|
851 | 0 | for (int position = 0; position < ADDRMAN_BUCKET_SIZE; ++position) { Branch (851:32): [True: 0, False: 0]
|
852 | 0 | int id = GetEntry(from_tried, bucket, position); |
853 | 0 | if (id >= 0) { Branch (853:17): [True: 0, False: 0]
|
854 | 0 | AddrInfo info = mapInfo.at(id); |
855 | 0 | AddressPosition location = AddressPosition( |
856 | 0 | from_tried, |
857 | 0 | /*multiplicity_in=*/from_tried ? 1 : info.nRefCount, Branch (857:41): [True: 0, False: 0]
|
858 | 0 | bucket, |
859 | 0 | position); |
860 | 0 | infos.emplace_back(info, location); |
861 | 0 | } |
862 | 0 | } |
863 | 0 | } |
864 | |
|
865 | 0 | return infos; |
866 | 0 | } |
867 | | |
868 | | void AddrManImpl::Connected_(const CService& addr, NodeSeconds time) |
869 | 290 | { |
870 | 290 | AssertLockHeld(cs); |
871 | | |
872 | 290 | AddrInfo* pinfo = Find(addr); |
873 | | |
874 | | // if not found, bail out |
875 | 290 | if (!pinfo) Branch (875:9): [True: 290, False: 0]
|
876 | 290 | return; |
877 | | |
878 | 0 | AddrInfo& info = *pinfo; |
879 | | |
880 | | // update info |
881 | 0 | const auto update_interval{20min}; |
882 | 0 | if (time - info.nTime > update_interval) { Branch (882:9): [True: 0, False: 0]
|
883 | 0 | info.nTime = time; |
884 | 0 | } |
885 | 0 | } |
886 | | |
887 | | void AddrManImpl::SetServices_(const CService& addr, ServiceFlags nServices) |
888 | 580 | { |
889 | 580 | AssertLockHeld(cs); |
890 | | |
891 | 580 | AddrInfo* pinfo = Find(addr); |
892 | | |
893 | | // if not found, bail out |
894 | 580 | if (!pinfo) Branch (894:9): [True: 580, False: 0]
|
895 | 580 | return; |
896 | | |
897 | 0 | AddrInfo& info = *pinfo; |
898 | | |
899 | | // update info |
900 | 0 | info.nServices = nServices; |
901 | 0 | } |
902 | | |
903 | | void AddrManImpl::ResolveCollisions_() |
904 | 0 | { |
905 | 0 | AssertLockHeld(cs); |
906 | |
|
907 | 0 | for (std::set<int>::iterator it = m_tried_collisions.begin(); it != m_tried_collisions.end();) { Branch (907:67): [True: 0, False: 0]
|
908 | 0 | int id_new = *it; |
909 | |
|
910 | 0 | bool erase_collision = false; |
911 | | |
912 | | // If id_new not found in mapInfo remove it from m_tried_collisions |
913 | 0 | if (mapInfo.count(id_new) != 1) { Branch (913:13): [True: 0, False: 0]
|
914 | 0 | erase_collision = true; |
915 | 0 | } else { |
916 | 0 | AddrInfo& info_new = mapInfo[id_new]; |
917 | | |
918 | | // Which tried bucket to move the entry to. |
919 | 0 | int tried_bucket = info_new.GetTriedBucket(nKey, m_netgroupman); |
920 | 0 | int tried_bucket_pos = info_new.GetBucketPosition(nKey, false, tried_bucket); |
921 | 0 | if (!info_new.IsValid()) { // id_new may no longer map to a valid address Branch (921:17): [True: 0, False: 0]
|
922 | 0 | erase_collision = true; |
923 | 0 | } else if (vvTried[tried_bucket][tried_bucket_pos] != -1) { // The position in the tried bucket is not empty Branch (923:24): [True: 0, False: 0]
|
924 | | |
925 | | // Get the to-be-evicted address that is being tested |
926 | 0 | int id_old = vvTried[tried_bucket][tried_bucket_pos]; |
927 | 0 | AddrInfo& info_old = mapInfo[id_old]; |
928 | |
|
929 | 0 | const auto current_time{Now<NodeSeconds>()}; |
930 | | |
931 | | // Has successfully connected in last X hours |
932 | 0 | if (current_time - info_old.m_last_success < ADDRMAN_REPLACEMENT) { Branch (932:21): [True: 0, False: 0]
|
933 | 0 | erase_collision = true; |
934 | 0 | } else if (current_time - info_old.m_last_try < ADDRMAN_REPLACEMENT) { // attempted to connect and failed in last X hours Branch (934:28): [True: 0, False: 0]
|
935 | | |
936 | | // Give address at least 60 seconds to successfully connect |
937 | 0 | if (current_time - info_old.m_last_try > 60s) { Branch (937:25): [True: 0, False: 0]
|
938 | 0 | LogPrint(BCLog::ADDRMAN, "Replacing %s with %s in tried table\n", info_old.ToStringAddrPort(), info_new.ToStringAddrPort()); |
939 | | |
940 | | // Replaces an existing address already in the tried table with the new address |
941 | 0 | Good_(info_new, false, current_time); |
942 | 0 | erase_collision = true; |
943 | 0 | } |
944 | 0 | } else if (current_time - info_new.m_last_success > ADDRMAN_TEST_WINDOW) { Branch (944:28): [True: 0, False: 0]
|
945 | | // If the collision hasn't resolved in some reasonable amount of time, |
946 | | // just evict the old entry -- we must not be able to |
947 | | // connect to it for some reason. |
948 | 0 | LogPrint(BCLog::ADDRMAN, "Unable to test; replacing %s with %s in tried table anyway\n", info_old.ToStringAddrPort(), info_new.ToStringAddrPort()); |
949 | 0 | Good_(info_new, false, current_time); |
950 | 0 | erase_collision = true; |
951 | 0 | } |
952 | 0 | } else { // Collision is not actually a collision anymore |
953 | 0 | Good_(info_new, false, Now<NodeSeconds>()); |
954 | 0 | erase_collision = true; |
955 | 0 | } |
956 | 0 | } |
957 | |
|
958 | 0 | if (erase_collision) { Branch (958:13): [True: 0, False: 0]
|
959 | 0 | m_tried_collisions.erase(it++); |
960 | 0 | } else { |
961 | 0 | it++; |
962 | 0 | } |
963 | 0 | } |
964 | 0 | } |
965 | | |
966 | | std::pair<CAddress, NodeSeconds> AddrManImpl::SelectTriedCollision_() |
967 | 0 | { |
968 | 0 | AssertLockHeld(cs); |
969 | |
|
970 | 0 | if (m_tried_collisions.size() == 0) return {}; Branch (970:9): [True: 0, False: 0]
|
971 | | |
972 | 0 | std::set<int>::iterator it = m_tried_collisions.begin(); |
973 | | |
974 | | // Selects a random element from m_tried_collisions |
975 | 0 | std::advance(it, insecure_rand.randrange(m_tried_collisions.size())); |
976 | 0 | int id_new = *it; |
977 | | |
978 | | // If id_new not found in mapInfo remove it from m_tried_collisions |
979 | 0 | if (mapInfo.count(id_new) != 1) { Branch (979:9): [True: 0, False: 0]
|
980 | 0 | m_tried_collisions.erase(it); |
981 | 0 | return {}; |
982 | 0 | } |
983 | | |
984 | 0 | const AddrInfo& newInfo = mapInfo[id_new]; |
985 | | |
986 | | // which tried bucket to move the entry to |
987 | 0 | int tried_bucket = newInfo.GetTriedBucket(nKey, m_netgroupman); |
988 | 0 | int tried_bucket_pos = newInfo.GetBucketPosition(nKey, false, tried_bucket); |
989 | |
|
990 | 0 | const AddrInfo& info_old = mapInfo[vvTried[tried_bucket][tried_bucket_pos]]; |
991 | 0 | return {info_old, info_old.m_last_try}; |
992 | 0 | } |
993 | | |
994 | | std::optional<AddressPosition> AddrManImpl::FindAddressEntry_(const CAddress& addr) |
995 | 0 | { |
996 | 0 | AssertLockHeld(cs); |
997 | |
|
998 | 0 | AddrInfo* addr_info = Find(addr); |
999 | |
|
1000 | 0 | if (!addr_info) return std::nullopt; Branch (1000:9): [True: 0, False: 0]
|
1001 | | |
1002 | 0 | if(addr_info->fInTried) { Branch (1002:8): [True: 0, False: 0]
|
1003 | 0 | int bucket{addr_info->GetTriedBucket(nKey, m_netgroupman)}; |
1004 | 0 | return AddressPosition(/*tried_in=*/true, |
1005 | 0 | /*multiplicity_in=*/1, |
1006 | 0 | /*bucket_in=*/bucket, |
1007 | 0 | /*position_in=*/addr_info->GetBucketPosition(nKey, false, bucket)); |
1008 | 0 | } else { |
1009 | 0 | int bucket{addr_info->GetNewBucket(nKey, m_netgroupman)}; |
1010 | 0 | return AddressPosition(/*tried_in=*/false, |
1011 | 0 | /*multiplicity_in=*/addr_info->nRefCount, |
1012 | 0 | /*bucket_in=*/bucket, |
1013 | 0 | /*position_in=*/addr_info->GetBucketPosition(nKey, true, bucket)); |
1014 | 0 | } |
1015 | 0 | } |
1016 | | |
1017 | | size_t AddrManImpl::Size_(std::optional<Network> net, std::optional<bool> in_new) const |
1018 | 0 | { |
1019 | 0 | AssertLockHeld(cs); |
1020 | |
|
1021 | 0 | if (!net.has_value()) { Branch (1021:9): [True: 0, False: 0]
|
1022 | 0 | if (in_new.has_value()) { Branch (1022:13): [True: 0, False: 0]
|
1023 | 0 | return *in_new ? nNew : nTried; Branch (1023:20): [True: 0, False: 0]
|
1024 | 0 | } else { |
1025 | 0 | return vRandom.size(); |
1026 | 0 | } |
1027 | 0 | } |
1028 | 0 | if (auto it = m_network_counts.find(*net); it != m_network_counts.end()) { Branch (1028:48): [True: 0, False: 0]
|
1029 | 0 | auto net_count = it->second; |
1030 | 0 | if (in_new.has_value()) { Branch (1030:13): [True: 0, False: 0]
|
1031 | 0 | return *in_new ? net_count.n_new : net_count.n_tried; Branch (1031:20): [True: 0, False: 0]
|
1032 | 0 | } else { |
1033 | 0 | return net_count.n_new + net_count.n_tried; |
1034 | 0 | } |
1035 | 0 | } |
1036 | 0 | return 0; |
1037 | 0 | } |
1038 | | |
1039 | | void AddrManImpl::Check() const |
1040 | 2.90k | { |
1041 | 2.90k | AssertLockHeld(cs); |
1042 | | |
1043 | | // Run consistency checks 1 in m_consistency_check_ratio times if enabled |
1044 | 2.90k | if (m_consistency_check_ratio == 0) return; Branch (1044:9): [True: 2.90k, False: 0]
|
1045 | 0 | if (insecure_rand.randrange(m_consistency_check_ratio) >= 1) return; Branch (1045:9): [True: 0, False: 0]
|
1046 | | |
1047 | 0 | const int err{CheckAddrman()}; |
1048 | 0 | if (err) { Branch (1048:9): [True: 0, False: 0]
|
1049 | 0 | LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err); |
1050 | 0 | assert(false); |
1051 | 0 | } |
1052 | 0 | } |
1053 | | |
1054 | | int AddrManImpl::CheckAddrman() const |
1055 | 0 | { |
1056 | 0 | AssertLockHeld(cs); |
1057 | |
|
1058 | 0 | LOG_TIME_MILLIS_WITH_CATEGORY_MSG_ONCE( |
1059 | 0 | strprintf("new %i, tried %i, total %u", nNew, nTried, vRandom.size()), BCLog::ADDRMAN); |
1060 | |
|
1061 | 0 | std::unordered_set<int> setTried; |
1062 | 0 | std::unordered_map<int, int> mapNew; |
1063 | 0 | std::unordered_map<Network, NewTriedCount> local_counts; |
1064 | |
|
1065 | 0 | if (vRandom.size() != (size_t)(nTried + nNew)) Branch (1065:9): [True: 0, False: 0]
|
1066 | 0 | return -7; |
1067 | | |
1068 | 0 | for (const auto& entry : mapInfo) { Branch (1068:28): [True: 0, False: 0]
|
1069 | 0 | int n = entry.first; |
1070 | 0 | const AddrInfo& info = entry.second; |
1071 | 0 | if (info.fInTried) { Branch (1071:13): [True: 0, False: 0]
|
1072 | 0 | if (!TicksSinceEpoch<std::chrono::seconds>(info.m_last_success)) { Branch (1072:17): [True: 0, False: 0]
|
1073 | 0 | return -1; |
1074 | 0 | } |
1075 | 0 | if (info.nRefCount) Branch (1075:17): [True: 0, False: 0]
|
1076 | 0 | return -2; |
1077 | 0 | setTried.insert(n); |
1078 | 0 | local_counts[info.GetNetwork()].n_tried++; |
1079 | 0 | } else { |
1080 | 0 | if (info.nRefCount < 0 || info.nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS) Branch (1080:17): [True: 0, False: 0]
Branch (1080:39): [True: 0, False: 0]
|
1081 | 0 | return -3; |
1082 | 0 | if (!info.nRefCount) Branch (1082:17): [True: 0, False: 0]
|
1083 | 0 | return -4; |
1084 | 0 | mapNew[n] = info.nRefCount; |
1085 | 0 | local_counts[info.GetNetwork()].n_new++; |
1086 | 0 | } |
1087 | 0 | const auto it{mapAddr.find(info)}; |
1088 | 0 | if (it == mapAddr.end() || it->second != n) { Branch (1088:13): [True: 0, False: 0]
Branch (1088:13): [True: 0, False: 0]
Branch (1088:36): [True: 0, False: 0]
|
1089 | 0 | return -5; |
1090 | 0 | } |
1091 | 0 | if (info.nRandomPos < 0 || (size_t)info.nRandomPos >= vRandom.size() || vRandom[info.nRandomPos] != n) Branch (1091:13): [True: 0, False: 0]
Branch (1091:36): [True: 0, False: 0]
Branch (1091:81): [True: 0, False: 0]
|
1092 | 0 | return -14; |
1093 | 0 | if (info.m_last_try < NodeSeconds{0s}) { Branch (1093:13): [True: 0, False: 0]
|
1094 | 0 | return -6; |
1095 | 0 | } |
1096 | 0 | if (info.m_last_success < NodeSeconds{0s}) { Branch (1096:13): [True: 0, False: 0]
|
1097 | 0 | return -8; |
1098 | 0 | } |
1099 | 0 | } |
1100 | | |
1101 | 0 | if (setTried.size() != (size_t)nTried) Branch (1101:9): [True: 0, False: 0]
|
1102 | 0 | return -9; |
1103 | 0 | if (mapNew.size() != (size_t)nNew) Branch (1103:9): [True: 0, False: 0]
|
1104 | 0 | return -10; |
1105 | | |
1106 | 0 | for (int n = 0; n < ADDRMAN_TRIED_BUCKET_COUNT; n++) { Branch (1106:21): [True: 0, False: 0]
|
1107 | 0 | for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) { Branch (1107:25): [True: 0, False: 0]
|
1108 | 0 | if (vvTried[n][i] != -1) { Branch (1108:17): [True: 0, False: 0]
|
1109 | 0 | if (!setTried.count(vvTried[n][i])) Branch (1109:21): [True: 0, False: 0]
|
1110 | 0 | return -11; |
1111 | 0 | const auto it{mapInfo.find(vvTried[n][i])}; |
1112 | 0 | if (it == mapInfo.end() || it->second.GetTriedBucket(nKey, m_netgroupman) != n) { Branch (1112:21): [True: 0, False: 0]
Branch (1112:21): [True: 0, False: 0]
Branch (1112:44): [True: 0, False: 0]
|
1113 | 0 | return -17; |
1114 | 0 | } |
1115 | 0 | if (it->second.GetBucketPosition(nKey, false, n) != i) { Branch (1115:21): [True: 0, False: 0]
|
1116 | 0 | return -18; |
1117 | 0 | } |
1118 | 0 | setTried.erase(vvTried[n][i]); |
1119 | 0 | } |
1120 | 0 | } |
1121 | 0 | } |
1122 | | |
1123 | 0 | for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) { Branch (1123:21): [True: 0, False: 0]
|
1124 | 0 | for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) { Branch (1124:25): [True: 0, False: 0]
|
1125 | 0 | if (vvNew[n][i] != -1) { Branch (1125:17): [True: 0, False: 0]
|
1126 | 0 | if (!mapNew.count(vvNew[n][i])) Branch (1126:21): [True: 0, False: 0]
|
1127 | 0 | return -12; |
1128 | 0 | const auto it{mapInfo.find(vvNew[n][i])}; |
1129 | 0 | if (it == mapInfo.end() || it->second.GetBucketPosition(nKey, true, n) != i) { Branch (1129:21): [True: 0, False: 0]
Branch (1129:21): [True: 0, False: 0]
Branch (1129:44): [True: 0, False: 0]
|
1130 | 0 | return -19; |
1131 | 0 | } |
1132 | 0 | if (--mapNew[vvNew[n][i]] == 0) Branch (1132:21): [True: 0, False: 0]
|
1133 | 0 | mapNew.erase(vvNew[n][i]); |
1134 | 0 | } |
1135 | 0 | } |
1136 | 0 | } |
1137 | | |
1138 | 0 | if (setTried.size()) Branch (1138:9): [True: 0, False: 0]
|
1139 | 0 | return -13; |
1140 | 0 | if (mapNew.size()) Branch (1140:9): [True: 0, False: 0]
|
1141 | 0 | return -15; |
1142 | 0 | if (nKey.IsNull()) Branch (1142:9): [True: 0, False: 0]
|
1143 | 0 | return -16; |
1144 | | |
1145 | | // It's possible that m_network_counts may have all-zero entries that local_counts |
1146 | | // doesn't have if addrs from a network were being added and then removed again in the past. |
1147 | 0 | if (m_network_counts.size() < local_counts.size()) { Branch (1147:9): [True: 0, False: 0]
|
1148 | 0 | return -20; |
1149 | 0 | } |
1150 | 0 | for (const auto& [net, count] : m_network_counts) { Branch (1150:35): [True: 0, False: 0]
|
1151 | 0 | if (local_counts[net].n_new != count.n_new || local_counts[net].n_tried != count.n_tried) { Branch (1151:13): [True: 0, False: 0]
Branch (1151:55): [True: 0, False: 0]
|
1152 | 0 | return -21; |
1153 | 0 | } |
1154 | 0 | } |
1155 | | |
1156 | 0 | return 0; |
1157 | 0 | } |
1158 | | |
1159 | | size_t AddrManImpl::Size(std::optional<Network> net, std::optional<bool> in_new) const |
1160 | 0 | { |
1161 | 0 | LOCK(cs); |
1162 | 0 | Check(); |
1163 | 0 | auto ret = Size_(net, in_new); |
1164 | 0 | Check(); |
1165 | 0 | return ret; |
1166 | 0 | } |
1167 | | |
1168 | | bool AddrManImpl::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty) |
1169 | 0 | { |
1170 | 0 | LOCK(cs); |
1171 | 0 | Check(); |
1172 | 0 | auto ret = Add_(vAddr, source, time_penalty); |
1173 | 0 | Check(); |
1174 | 0 | return ret; |
1175 | 0 | } |
1176 | | |
1177 | | bool AddrManImpl::Good(const CService& addr, NodeSeconds time) |
1178 | 580 | { |
1179 | 580 | LOCK(cs); |
1180 | 580 | Check(); |
1181 | 580 | auto ret = Good_(addr, /*test_before_evict=*/true, time); |
1182 | 580 | Check(); |
1183 | 580 | return ret; |
1184 | 580 | } |
1185 | | |
1186 | | void AddrManImpl::Attempt(const CService& addr, bool fCountFailure, NodeSeconds time) |
1187 | 0 | { |
1188 | 0 | LOCK(cs); |
1189 | 0 | Check(); |
1190 | 0 | Attempt_(addr, fCountFailure, time); |
1191 | 0 | Check(); |
1192 | 0 | } |
1193 | | |
1194 | | void AddrManImpl::ResolveCollisions() |
1195 | 0 | { |
1196 | 0 | LOCK(cs); |
1197 | 0 | Check(); |
1198 | 0 | ResolveCollisions_(); |
1199 | 0 | Check(); |
1200 | 0 | } |
1201 | | |
1202 | | std::pair<CAddress, NodeSeconds> AddrManImpl::SelectTriedCollision() |
1203 | 0 | { |
1204 | 0 | LOCK(cs); |
1205 | 0 | Check(); |
1206 | 0 | auto ret = SelectTriedCollision_(); |
1207 | 0 | Check(); |
1208 | 0 | return ret; |
1209 | 0 | } |
1210 | | |
1211 | | std::pair<CAddress, NodeSeconds> AddrManImpl::Select(bool new_only, std::optional<Network> network) const |
1212 | 0 | { |
1213 | 0 | LOCK(cs); |
1214 | 0 | Check(); |
1215 | 0 | auto addrRet = Select_(new_only, network); |
1216 | 0 | Check(); |
1217 | 0 | return addrRet; |
1218 | 0 | } |
1219 | | |
1220 | | std::vector<CAddress> AddrManImpl::GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network, const bool filtered) const |
1221 | 0 | { |
1222 | 0 | LOCK(cs); |
1223 | 0 | Check(); |
1224 | 0 | auto addresses = GetAddr_(max_addresses, max_pct, network, filtered); |
1225 | 0 | Check(); |
1226 | 0 | return addresses; |
1227 | 0 | } |
1228 | | |
1229 | | std::vector<std::pair<AddrInfo, AddressPosition>> AddrManImpl::GetEntries(bool from_tried) const |
1230 | 0 | { |
1231 | 0 | LOCK(cs); |
1232 | 0 | Check(); |
1233 | 0 | auto addrInfos = GetEntries_(from_tried); |
1234 | 0 | Check(); |
1235 | 0 | return addrInfos; |
1236 | 0 | } |
1237 | | |
1238 | | void AddrManImpl::Connected(const CService& addr, NodeSeconds time) |
1239 | 290 | { |
1240 | 290 | LOCK(cs); |
1241 | 290 | Check(); |
1242 | 290 | Connected_(addr, time); |
1243 | 290 | Check(); |
1244 | 290 | } |
1245 | | |
1246 | | void AddrManImpl::SetServices(const CService& addr, ServiceFlags nServices) |
1247 | 580 | { |
1248 | 580 | LOCK(cs); |
1249 | 580 | Check(); |
1250 | 580 | SetServices_(addr, nServices); |
1251 | 580 | Check(); |
1252 | 580 | } |
1253 | | |
1254 | | std::optional<AddressPosition> AddrManImpl::FindAddressEntry(const CAddress& addr) |
1255 | 0 | { |
1256 | 0 | LOCK(cs); |
1257 | 0 | Check(); |
1258 | 0 | auto entry = FindAddressEntry_(addr); |
1259 | 0 | Check(); |
1260 | 0 | return entry; |
1261 | 0 | } |
1262 | | |
1263 | | AddrMan::AddrMan(const NetGroupManager& netgroupman, bool deterministic, int32_t consistency_check_ratio) |
1264 | 0 | : m_impl(std::make_unique<AddrManImpl>(netgroupman, deterministic, consistency_check_ratio)) {} |
1265 | | |
1266 | 1 | AddrMan::~AddrMan() = default; |
1267 | | |
1268 | | template <typename Stream> |
1269 | | void AddrMan::Serialize(Stream& s_) const |
1270 | 0 | { |
1271 | 0 | m_impl->Serialize<Stream>(s_); |
1272 | 0 | } Unexecuted instantiation: void AddrMan::Serialize<HashedSourceWriter<AutoFile> >(HashedSourceWriter<AutoFile>&) const Unexecuted instantiation: void AddrMan::Serialize<DataStream>(DataStream&) const |
1273 | | |
1274 | | template <typename Stream> |
1275 | | void AddrMan::Unserialize(Stream& s_) |
1276 | 0 | { |
1277 | 0 | m_impl->Unserialize<Stream>(s_); |
1278 | 0 | } Unexecuted instantiation: void AddrMan::Unserialize<AutoFile>(AutoFile&) Unexecuted instantiation: void AddrMan::Unserialize<HashVerifier<AutoFile> >(HashVerifier<AutoFile>&) Unexecuted instantiation: void AddrMan::Unserialize<DataStream>(DataStream&) Unexecuted instantiation: void AddrMan::Unserialize<HashVerifier<DataStream> >(HashVerifier<DataStream>&) |
1279 | | |
1280 | | // explicit instantiation |
1281 | | template void AddrMan::Serialize(HashedSourceWriter<AutoFile>&) const; |
1282 | | template void AddrMan::Serialize(DataStream&) const; |
1283 | | template void AddrMan::Unserialize(AutoFile&); |
1284 | | template void AddrMan::Unserialize(HashVerifier<AutoFile>&); |
1285 | | template void AddrMan::Unserialize(DataStream&); |
1286 | | template void AddrMan::Unserialize(HashVerifier<DataStream>&); |
1287 | | |
1288 | | size_t AddrMan::Size(std::optional<Network> net, std::optional<bool> in_new) const |
1289 | 0 | { |
1290 | 0 | return m_impl->Size(net, in_new); |
1291 | 0 | } |
1292 | | |
1293 | | bool AddrMan::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty) |
1294 | 0 | { |
1295 | 0 | return m_impl->Add(vAddr, source, time_penalty); |
1296 | 0 | } |
1297 | | |
1298 | | bool AddrMan::Good(const CService& addr, NodeSeconds time) |
1299 | 580 | { |
1300 | 580 | return m_impl->Good(addr, time); |
1301 | 580 | } |
1302 | | |
1303 | | void AddrMan::Attempt(const CService& addr, bool fCountFailure, NodeSeconds time) |
1304 | 0 | { |
1305 | 0 | m_impl->Attempt(addr, fCountFailure, time); |
1306 | 0 | } |
1307 | | |
1308 | | void AddrMan::ResolveCollisions() |
1309 | 0 | { |
1310 | 0 | m_impl->ResolveCollisions(); |
1311 | 0 | } |
1312 | | |
1313 | | std::pair<CAddress, NodeSeconds> AddrMan::SelectTriedCollision() |
1314 | 0 | { |
1315 | 0 | return m_impl->SelectTriedCollision(); |
1316 | 0 | } |
1317 | | |
1318 | | std::pair<CAddress, NodeSeconds> AddrMan::Select(bool new_only, std::optional<Network> network) const |
1319 | 0 | { |
1320 | 0 | return m_impl->Select(new_only, network); |
1321 | 0 | } |
1322 | | |
1323 | | std::vector<CAddress> AddrMan::GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network, const bool filtered) const |
1324 | 0 | { |
1325 | 0 | return m_impl->GetAddr(max_addresses, max_pct, network, filtered); |
1326 | 0 | } |
1327 | | |
1328 | | std::vector<std::pair<AddrInfo, AddressPosition>> AddrMan::GetEntries(bool use_tried) const |
1329 | 0 | { |
1330 | 0 | return m_impl->GetEntries(use_tried); |
1331 | 0 | } |
1332 | | |
1333 | | void AddrMan::Connected(const CService& addr, NodeSeconds time) |
1334 | 290 | { |
1335 | 290 | m_impl->Connected(addr, time); |
1336 | 290 | } |
1337 | | |
1338 | | void AddrMan::SetServices(const CService& addr, ServiceFlags nServices) |
1339 | 580 | { |
1340 | 580 | m_impl->SetServices(addr, nServices); |
1341 | 580 | } |
1342 | | |
1343 | | std::optional<AddressPosition> AddrMan::FindAddressEntry(const CAddress& addr) |
1344 | 0 | { |
1345 | 0 | return m_impl->FindAddressEntry(addr); |
1346 | 0 | } |