Skip to content

Commit 4ee7845

Browse files
committed
Merge bitcoin/bitcoin#23826: test: Make AddrMan unit tests use public interface, extend coverage
ea4c9fd test: Cover eviction by timeout in addrman_evictionworks (Martin Zumsande) 4f1bb46 test: Add test for multiplicity in addrman new tables (Martin Zumsande) e880bb7 test: Add test for updating addrman entries (Martin Zumsande) f02eee8 test: introduce utility function to retrieve an addrman (Martin Zumsande) f0e5efb test: Remove unused AddrManTest class (Martin Zumsande) b696d78 test: Remove tests for internal helper functions (Martin Zumsande) 0538520 test: use AddrMan instead of AddrManTest where possible (Martin Zumsande) 1c65d42 test: Inline SimConnFail function (Martin Zumsande) 5b7aac3 test: delete unused GetBucketAndEntry function (Amiti Uttarwar) 2ba1e74 test: Update addrman_serialization unit test to use AddrMan's interface (Amiti Uttarwar) dad5f76 addrman: Introduce a test-only function to lookup addresses (Amiti Uttarwar) Pull request description: This PR (joint work with Amiti Uttarwar) changes the addrman unit tests such that they only use the public `AddrMan` interface: This has the advantage that the tests are less implementation-dependent, i.e. it would be possible to rewrite the internal addrman implementation (as drafted [here](https://github.com/sipa/bitcoin/tree/202106_multiindex_addrman) for using a multiindex) without having to adjust the tests. This includes the following steps: * Adding a test-only function `FindAddressEntry()` to the public addrman interface which returns info about an address in addrman (e.g. bucket, position, whethe the address is in new or tried). Obviously we want to do this sparingly, but I think a single test-only function is ok (which could also be useful elsewhere, e.g. in fuzz tests). * Removal of the `AddrManTest` subclass which would reach into AddrMan's internals, using `AddrMan` instead * Removal of tests for internal helper functions that are not publicly exposed (these are still tested indirectly via the public functions calling them). * Additional tests for previously untested features such as multiplicity in the new tables, that can be tested with the help of `FindAddressEntry()`. All in all, this PR increases the unit test coverage of AddrMan by a bit. ACKs for top commit: jnewbery: ACK ea4c9fd josibake: reACK bitcoin/bitcoin@ea4c9fd Tree-SHA512: c2d4ec8bdc62ffd6055ddcd37dea85ec08c76889e9e417e8d7c62a96cf68a8bcbe8c67bec3344d91fa7d3c499f6d9f810962da1dddd38e70966186b10b8ab447
2 parents 300124d + ea4c9fd commit 4ee7845

File tree

4 files changed

+285
-268
lines changed

4 files changed

+285
-268
lines changed

src/addrman.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,29 @@ std::pair<CAddress, int64_t> AddrManImpl::SelectTriedCollision_()
930930
return {info_old, info_old.nLastTry};
931931
}
932932

933+
std::optional<AddressPosition> AddrManImpl::FindAddressEntry_(const CAddress& addr)
934+
{
935+
AssertLockHeld(cs);
936+
937+
AddrInfo* addr_info = Find(addr);
938+
939+
if (!addr_info) return std::nullopt;
940+
941+
if(addr_info->fInTried) {
942+
int bucket{addr_info->GetTriedBucket(nKey, m_asmap)};
943+
return AddressPosition(/*tried=*/true,
944+
/*multiplicity=*/1,
945+
/*bucket=*/bucket,
946+
/*position=*/addr_info->GetBucketPosition(nKey, false, bucket));
947+
} else {
948+
int bucket{addr_info->GetNewBucket(nKey, m_asmap)};
949+
return AddressPosition(/*tried=*/false,
950+
/*multiplicity=*/addr_info->nRefCount,
951+
/*bucket=*/bucket,
952+
/*position=*/addr_info->GetBucketPosition(nKey, true, bucket));
953+
}
954+
}
955+
933956
void AddrManImpl::Check() const
934957
{
935958
AssertLockHeld(cs);
@@ -1116,6 +1139,15 @@ void AddrManImpl::SetServices(const CService& addr, ServiceFlags nServices)
11161139
Check();
11171140
}
11181141

1142+
std::optional<AddressPosition> AddrManImpl::FindAddressEntry(const CAddress& addr)
1143+
{
1144+
LOCK(cs);
1145+
Check();
1146+
auto entry = FindAddressEntry_(addr);
1147+
Check();
1148+
return entry;
1149+
}
1150+
11191151
const std::vector<bool>& AddrManImpl::GetAsmap() const
11201152
{
11211153
return m_asmap;
@@ -1201,3 +1233,8 @@ const std::vector<bool>& AddrMan::GetAsmap() const
12011233
{
12021234
return m_impl->GetAsmap();
12031235
}
1236+
1237+
std::optional<AddressPosition> AddrMan::FindAddressEntry(const CAddress& addr)
1238+
{
1239+
return m_impl->FindAddressEntry(addr);
1240+
}

src/addrman.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,31 @@ class AddrManImpl;
2222
/** Default for -checkaddrman */
2323
static constexpr int32_t DEFAULT_ADDRMAN_CONSISTENCY_CHECKS{0};
2424

25+
/** Test-only struct, capturing info about an address in AddrMan */
26+
struct AddressPosition {
27+
// Whether the address is in the new or tried table
28+
const bool tried;
29+
30+
// Addresses in the tried table should always have a multiplicity of 1.
31+
// Addresses in the new table can have multiplicity between 1 and
32+
// ADDRMAN_NEW_BUCKETS_PER_ADDRESS
33+
const int multiplicity;
34+
35+
// If the address is in the new table, the bucket and position are
36+
// populated based on the first source who sent the address.
37+
// In certain edge cases, this may not be where the address is currently
38+
// located.
39+
const int bucket;
40+
const int position;
41+
42+
bool operator==(AddressPosition other) {
43+
return std::tie(tried, multiplicity, bucket, position) ==
44+
std::tie(other.tried, other.multiplicity, other.bucket, other.position);
45+
}
46+
explicit AddressPosition(bool tried_in, int multiplicity_in, int bucket_in, int position_in)
47+
: tried{tried_in}, multiplicity{multiplicity_in}, bucket{bucket_in}, position{position_in} {}
48+
};
49+
2550
/** Stochastic address manager
2651
*
2752
* Design goals:
@@ -142,6 +167,15 @@ class AddrMan
142167
void SetServices(const CService& addr, ServiceFlags nServices);
143168

144169
const std::vector<bool>& GetAsmap() const;
170+
171+
/** Test-only function
172+
* Find the address record in AddrMan and return information about its
173+
* position.
174+
* @param[in] addr The address record to look up.
175+
* @return Information about the address record in AddrMan
176+
* or nullopt if address is not found.
177+
*/
178+
std::optional<AddressPosition> FindAddressEntry(const CAddress& addr);
145179
};
146180

147181
#endif // BITCOIN_ADDRMAN_H

src/addrman_impl.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,11 @@ class AddrManImpl
137137
void SetServices(const CService& addr, ServiceFlags nServices)
138138
EXCLUSIVE_LOCKS_REQUIRED(!cs);
139139

140+
std::optional<AddressPosition> FindAddressEntry(const CAddress& addr)
141+
EXCLUSIVE_LOCKS_REQUIRED(!cs);
142+
140143
const std::vector<bool>& GetAsmap() const;
141144

142-
friend class AddrManTest;
143145
friend class AddrManDeterministic;
144146

145147
private:
@@ -266,6 +268,8 @@ class AddrManImpl
266268

267269
std::pair<CAddress, int64_t> SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs);
268270

271+
std::optional<AddressPosition> FindAddressEntry_(const CAddress& addr) EXCLUSIVE_LOCKS_REQUIRED(cs);
272+
269273
//! Consistency check, taking into account m_consistency_check_ratio.
270274
//! Will std::abort if an inconsistency is detected.
271275
void Check() const EXCLUSIVE_LOCKS_REQUIRED(cs);

0 commit comments

Comments
 (0)