1
1
mirror of https://github.com/bitcoin/bitcoin.git synced 2024-05-17 23:56:39 +00:00

Merge bitcoin/bitcoin#20233: addrman: Make consistency checks a runtime option

a4d78546b0858602c60c03fdf8b35ca666ab2e56 [addrman] Make addrman consistency checks a runtime option (John Newbery)
10aac241455a3270462d49b53732477ed97623e7 [tests] Make deterministic addrman use nKey = 1 (John Newbery)
fa9710f62c29c7f8d71c9f281001c9b5e70946bf [addrman] Add deterministic argument to CAddrMan ctor (John Newbery)
ee458d84fc187d69f002ebead6fccc4f4f9c0744 Add missing const to CAddrMan::Check_() (MarcoFalke)

Pull request description:

  CAddrMan has internal consistency checks. Currently, these are only run when the program is compiled with the  `DEBUG_ADDRMAN` option. This option is not enabled on any of our CI builds, and it's likely that no-one is running them at all.

  This PR makes consistency checks a (hidden) runtime option that can be enabled with `-checkaddrman`, where `-checkaddrman=n` will result in the consistency checks running every n operations (similar to `-checkmempool=n`). We set the ratio to 1/100 for our unit tests, and leave it disabled by default for all networks. Additionally, a consistency check failure now asserts, rather than logging and continuing. This matches the behavior of CTxMemPool and TxRequestTracker, where a failed consistency check asserts.

ACKs for top commit:
  jonatack:
    ACK a4d78546b0858602c60c03fdf8b35ca666ab2e56 per `git diff 00fd089 a4d7854`, tested by adding logging similar to #22479 and running with `-checkaddrman=<n>` for various values 0/1/10/100 etc, tested the updated docs with `bitcoind -help-debug | grep -A2 "checkaddrman\|checkmempool"` and verified rebased on master that compiling with `CPPFLAGS="-DDEBUG_ADDRMAN"` no longer causes the build to error.
  mzumsande:
    Code-review ACK a4d78546b0858602c60c03fdf8b35ca666ab2e56
  theStack:
    Code-review ACK a4d78546b0858602c60c03fdf8b35ca666ab2e56

Tree-SHA512: eaee003f7a99154822c5b5efbc62008d32c1efbecc6fec6e183427f6b2ae5d30b3be7924e3a7271b1a1de91517f5bd2a70011d45358c3105c6a0702f12b70f7c
This commit is contained in:
fanquake 2021-08-13 16:39:01 +08:00
commit 803ef70fd9
No known key found for this signature in database
GPG Key ID: 2EEB9F5CC09526C1
11 changed files with 113 additions and 104 deletions

View File

@ -431,11 +431,14 @@ CAddrInfo CAddrMan::Select_(bool newOnly) const
} }
} }
#ifdef DEBUG_ADDRMAN int CAddrMan::Check_() const
int CAddrMan::Check_()
{ {
AssertLockHeld(cs); AssertLockHeld(cs);
// Run consistency checks 1 in m_consistency_check_ratio times if enabled
if (m_consistency_check_ratio == 0) return 0;
if (insecure_rand.randrange(m_consistency_check_ratio) >= 1) return 0;
std::unordered_set<int> setTried; std::unordered_set<int> setTried;
std::unordered_map<int, int> mapNew; std::unordered_map<int, int> mapNew;
@ -458,8 +461,10 @@ int CAddrMan::Check_()
return -4; return -4;
mapNew[n] = info.nRefCount; mapNew[n] = info.nRefCount;
} }
if (mapAddr[info] != n) const auto it{mapAddr.find(info)};
if (it == mapAddr.end() || it->second != n) {
return -5; return -5;
}
if (info.nRandomPos < 0 || (size_t)info.nRandomPos >= vRandom.size() || vRandom[info.nRandomPos] != n) if (info.nRandomPos < 0 || (size_t)info.nRandomPos >= vRandom.size() || vRandom[info.nRandomPos] != n)
return -14; return -14;
if (info.nLastTry < 0) if (info.nLastTry < 0)
@ -478,10 +483,13 @@ int CAddrMan::Check_()
if (vvTried[n][i] != -1) { if (vvTried[n][i] != -1) {
if (!setTried.count(vvTried[n][i])) if (!setTried.count(vvTried[n][i]))
return -11; return -11;
if (mapInfo[vvTried[n][i]].GetTriedBucket(nKey, m_asmap) != n) const auto it{mapInfo.find(vvTried[n][i])};
if (it == mapInfo.end() || it->second.GetTriedBucket(nKey, m_asmap) != n) {
return -17; return -17;
if (mapInfo[vvTried[n][i]].GetBucketPosition(nKey, false, n) != i) }
if (it->second.GetBucketPosition(nKey, false, n) != i) {
return -18; return -18;
}
setTried.erase(vvTried[n][i]); setTried.erase(vvTried[n][i]);
} }
} }
@ -492,8 +500,10 @@ int CAddrMan::Check_()
if (vvNew[n][i] != -1) { if (vvNew[n][i] != -1) {
if (!mapNew.count(vvNew[n][i])) if (!mapNew.count(vvNew[n][i]))
return -12; return -12;
if (mapInfo[vvNew[n][i]].GetBucketPosition(nKey, true, n) != i) const auto it{mapInfo.find(vvNew[n][i])};
if (it == mapInfo.end() || it->second.GetBucketPosition(nKey, true, n) != i) {
return -19; return -19;
}
if (--mapNew[vvNew[n][i]] == 0) if (--mapNew[vvNew[n][i]] == 0)
mapNew.erase(vvNew[n][i]); mapNew.erase(vvNew[n][i]);
} }
@ -509,7 +519,6 @@ int CAddrMan::Check_()
return 0; return 0;
} }
#endif
void CAddrMan::GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size_t max_pct, std::optional<Network> network) const void CAddrMan::GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size_t max_pct, std::optional<Network> network) const
{ {

View File

@ -26,6 +26,9 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
/** Default for -checkaddrman */
static constexpr int32_t DEFAULT_ADDRMAN_CONSISTENCY_CHECKS{0};
/** /**
* Extended statistics about a CAddress * Extended statistics about a CAddress
*/ */
@ -124,8 +127,8 @@ public:
* attempt was unsuccessful. * attempt was unsuccessful.
* * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not * * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not
* be observable by adversaries. * be observable by adversaries.
* * Several indexes are kept for high performance. Defining DEBUG_ADDRMAN will introduce frequent (and expensive) * * Several indexes are kept for high performance. Setting m_consistency_check_ratio with the -checkaddrman
* consistency checks for the entire data structure. * configuration option will introduce (expensive) consistency checks for the entire data structure.
*/ */
//! total number of buckets for tried addresses //! total number of buckets for tried addresses
@ -493,9 +496,12 @@ public:
mapAddr.clear(); mapAddr.clear();
} }
CAddrMan() explicit CAddrMan(bool deterministic, int32_t consistency_check_ratio)
: insecure_rand{deterministic},
m_consistency_check_ratio{consistency_check_ratio}
{ {
Clear(); Clear();
if (deterministic) nKey = uint256{1};
} }
~CAddrMan() ~CAddrMan()
@ -637,13 +643,13 @@ protected:
//! secret key to randomize bucket select with //! secret key to randomize bucket select with
uint256 nKey; uint256 nKey;
//! Source of random numbers for randomization in inner loops
mutable FastRandomContext insecure_rand GUARDED_BY(cs);
//! A mutex to protect the inner data structures. //! A mutex to protect the inner data structures.
mutable Mutex cs; mutable Mutex cs;
private: private:
//! Source of random numbers for randomization in inner loops
mutable FastRandomContext insecure_rand GUARDED_BY(cs);
//! Serialization versions. //! Serialization versions.
enum Format : uint8_t { enum Format : uint8_t {
V0_HISTORICAL = 0, //!< historic format, before commit e6b343d88 V0_HISTORICAL = 0, //!< historic format, before commit e6b343d88
@ -698,6 +704,9 @@ private:
//! Holds addrs inserted into tried table that collide with existing entries. Test-before-evict discipline used to resolve these collisions. //! Holds addrs inserted into tried table that collide with existing entries. Test-before-evict discipline used to resolve these collisions.
std::set<int> m_tried_collisions; std::set<int> m_tried_collisions;
/** Perform consistency checks every m_consistency_check_ratio operations (if non-zero). */
const int32_t m_consistency_check_ratio;
//! Find an entry. //! Find an entry.
CAddrInfo* Find(const CNetAddr& addr, int *pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs); CAddrInfo* Find(const CNetAddr& addr, int *pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
@ -735,22 +744,19 @@ private:
CAddrInfo SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs); CAddrInfo SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs);
//! Consistency check //! Consistency check
void Check() const void Check() const EXCLUSIVE_LOCKS_REQUIRED(cs)
EXCLUSIVE_LOCKS_REQUIRED(cs)
{ {
#ifdef DEBUG_ADDRMAN
AssertLockHeld(cs); AssertLockHeld(cs);
const int err = Check_(); const int err = Check_();
if (err) { if (err) {
LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err); LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
assert(false);
} }
#endif
} }
#ifdef DEBUG_ADDRMAN
//! Perform consistency check. Returns an error code or zero. //! Perform consistency check. Returns an error code or zero.
int Check_() const EXCLUSIVE_LOCKS_REQUIRED(cs); int Check_() const EXCLUSIVE_LOCKS_REQUIRED(cs);
#endif
/** /**
* Return all or many randomly selected addresses, optionally by network. * Return all or many randomly selected addresses, optionally by network.

View File

@ -72,7 +72,7 @@ static void AddrManAdd(benchmark::Bench& bench)
{ {
CreateAddresses(); CreateAddresses();
CAddrMan addrman; CAddrMan addrman(/* deterministic */ false, /* consistency_check_ratio */ 0);
bench.run([&] { bench.run([&] {
AddAddressesToAddrMan(addrman); AddAddressesToAddrMan(addrman);
@ -82,7 +82,7 @@ static void AddrManAdd(benchmark::Bench& bench)
static void AddrManSelect(benchmark::Bench& bench) static void AddrManSelect(benchmark::Bench& bench)
{ {
CAddrMan addrman; CAddrMan addrman(/* deterministic */ false, /* consistency_check_ratio */ 0);
FillAddrMan(addrman); FillAddrMan(addrman);
@ -94,7 +94,7 @@ static void AddrManSelect(benchmark::Bench& bench)
static void AddrManGetAddr(benchmark::Bench& bench) static void AddrManGetAddr(benchmark::Bench& bench)
{ {
CAddrMan addrman; CAddrMan addrman(/* deterministic */ false, /* consistency_check_ratio */ 0);
FillAddrMan(addrman); FillAddrMan(addrman);
@ -112,10 +112,12 @@ static void AddrManGood(benchmark::Bench& bench)
* we want to do the same amount of work in every loop iteration. */ * we want to do the same amount of work in every loop iteration. */
bench.epochs(5).epochIterations(1); bench.epochs(5).epochIterations(1);
const size_t addrman_count{bench.epochs() * bench.epochIterations()};
std::vector<CAddrMan> addrmans(bench.epochs() * bench.epochIterations()); std::vector<std::unique_ptr<CAddrMan>> addrmans(addrman_count);
for (auto& addrman : addrmans) { for (size_t i{0}; i < addrman_count; ++i) {
FillAddrMan(addrman); addrmans[i] = std::make_unique<CAddrMan>(/* deterministic */ false, /* consistency_check_ratio */ 0);
FillAddrMan(*addrmans[i]);
} }
auto markSomeAsGood = [](CAddrMan& addrman) { auto markSomeAsGood = [](CAddrMan& addrman) {
@ -130,7 +132,7 @@ static void AddrManGood(benchmark::Bench& bench)
uint64_t i = 0; uint64_t i = 0;
bench.run([&] { bench.run([&] {
markSomeAsGood(addrmans.at(i)); markSomeAsGood(*addrmans.at(i));
++i; ++i;
}); });
} }

View File

@ -501,7 +501,8 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-checkblocks=<n>", strprintf("How many blocks to check at startup (default: %u, 0 = all)", DEFAULT_CHECKBLOCKS), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-checkblocks=<n>", strprintf("How many blocks to check at startup (default: %u, 0 = all)", DEFAULT_CHECKBLOCKS), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-checklevel=<n>", strprintf("How thorough the block verification of -checkblocks is: %s (0-4, default: %u)", Join(CHECKLEVEL_DOC, ", "), DEFAULT_CHECKLEVEL), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-checklevel=<n>", strprintf("How thorough the block verification of -checkblocks is: %s (0-4, default: %u)", Join(CHECKLEVEL_DOC, ", "), DEFAULT_CHECKLEVEL), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-checkblockindex", strprintf("Do a consistency check for the block tree, chainstate, and other validation data structures occasionally. (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-checkblockindex", strprintf("Do a consistency check for the block tree, chainstate, and other validation data structures occasionally. (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-checkmempool=<n>", strprintf("Run checks every <n> transactions (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-checkaddrman=<n>", strprintf("Run addrman consistency checks every <n> operations. Use 0 to disable. (default: %u)", DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-checkmempool=<n>", strprintf("Run mempool consistency checks every <n> transactions. Use 0 to disable. (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-checkpoints", strprintf("Enable rejection of any forks from the known historical chain until block %s (default: %u)", defaultChainParams->Checkpoints().GetHeight(), DEFAULT_CHECKPOINTS_ENABLED), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-checkpoints", strprintf("Enable rejection of any forks from the known historical chain until block %s (default: %u)", defaultChainParams->Checkpoints().GetHeight(), DEFAULT_CHECKPOINTS_ENABLED), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-deprecatedrpc=<method>", "Allows deprecated RPC method(s) to be used", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-deprecatedrpc=<method>", "Allows deprecated RPC method(s) to be used", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
@ -1164,7 +1165,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
const bool ignores_incoming_txs{args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)}; const bool ignores_incoming_txs{args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)};
assert(!node.addrman); assert(!node.addrman);
node.addrman = std::make_unique<CAddrMan>(); auto check_addrman = std::clamp<int32_t>(args.GetArg("-checkaddrman", DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), 0, 1000000);
node.addrman = std::make_unique<CAddrMan>(/* deterministic */ false, /* consistency_check_ratio */ check_addrman);
assert(!node.banman); assert(!node.banman);
node.banman = std::make_unique<BanMan>(gArgs.GetDataDirNet() / "banlist", &uiInterface, args.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME)); node.banman = std::make_unique<BanMan>(gArgs.GetDataDirNet() / "banlist", &uiInterface, args.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME));
assert(!node.connman); assert(!node.connman);

View File

@ -22,23 +22,12 @@ private:
public: public:
explicit CAddrManTest(bool makeDeterministic = true, explicit CAddrManTest(bool makeDeterministic = true,
std::vector<bool> asmap = std::vector<bool>()) std::vector<bool> asmap = std::vector<bool>())
: CAddrMan(makeDeterministic, /* consistency_check_ratio */ 100)
{ {
if (makeDeterministic) {
// Set addrman addr placement to be deterministic.
MakeDeterministic();
}
deterministic = makeDeterministic; deterministic = makeDeterministic;
m_asmap = asmap; m_asmap = asmap;
} }
//! Ensure that bucket placement is always the same for testing purposes.
void MakeDeterministic()
{
LOCK(cs);
nKey.SetNull();
insecure_rand = FastRandomContext(true);
}
CAddrInfo* Find(const CNetAddr& addr, int* pnId = nullptr) CAddrInfo* Find(const CNetAddr& addr, int* pnId = nullptr)
{ {
LOCK(cs); LOCK(cs);
@ -89,7 +78,7 @@ public:
CAddrMan::Clear(); CAddrMan::Clear();
if (deterministic) { if (deterministic) {
LOCK(cs); LOCK(cs);
nKey.SetNull(); nKey = uint256{1};
insecure_rand = FastRandomContext(true); insecure_rand = FastRandomContext(true);
} }
} }
@ -267,24 +256,27 @@ BOOST_AUTO_TEST_CASE(addrman_new_collisions)
CNetAddr source = ResolveIP("252.2.2.2"); CNetAddr source = ResolveIP("252.2.2.2");
BOOST_CHECK_EQUAL(addrman.size(), 0U); uint32_t num_addrs{0};
for (unsigned int i = 1; i < 18; i++) { BOOST_CHECK_EQUAL(addrman.size(), num_addrs);
CService addr = ResolveService("250.1.1." + ToString(i));
while (num_addrs < 22) { // Magic number! 250.1.1.1 - 250.1.1.22 do not collide with deterministic key = 1
CService addr = ResolveService("250.1.1." + ToString(++num_addrs));
BOOST_CHECK(addrman.Add(CAddress(addr, NODE_NONE), source)); BOOST_CHECK(addrman.Add(CAddress(addr, NODE_NONE), source));
//Test: No collision in new table yet. //Test: No collision in new table yet.
BOOST_CHECK_EQUAL(addrman.size(), i); BOOST_CHECK_EQUAL(addrman.size(), num_addrs);
} }
//Test: new table collision! //Test: new table collision!
CService addr1 = ResolveService("250.1.1.18"); CService addr1 = ResolveService("250.1.1." + ToString(++num_addrs));
uint32_t collisions{1};
BOOST_CHECK(addrman.Add(CAddress(addr1, NODE_NONE), source)); BOOST_CHECK(addrman.Add(CAddress(addr1, NODE_NONE), source));
BOOST_CHECK_EQUAL(addrman.size(), 17U); BOOST_CHECK_EQUAL(addrman.size(), num_addrs - collisions);
CService addr2 = ResolveService("250.1.1.19"); CService addr2 = ResolveService("250.1.1." + ToString(++num_addrs));
BOOST_CHECK(addrman.Add(CAddress(addr2, NODE_NONE), source)); BOOST_CHECK(addrman.Add(CAddress(addr2, NODE_NONE), source));
BOOST_CHECK_EQUAL(addrman.size(), 18U); BOOST_CHECK_EQUAL(addrman.size(), num_addrs - collisions);
} }
BOOST_AUTO_TEST_CASE(addrman_tried_collisions) BOOST_AUTO_TEST_CASE(addrman_tried_collisions)
@ -293,25 +285,28 @@ BOOST_AUTO_TEST_CASE(addrman_tried_collisions)
CNetAddr source = ResolveIP("252.2.2.2"); CNetAddr source = ResolveIP("252.2.2.2");
BOOST_CHECK_EQUAL(addrman.size(), 0U); uint32_t num_addrs{0};
for (unsigned int i = 1; i < 80; i++) { BOOST_CHECK_EQUAL(addrman.size(), num_addrs);
CService addr = ResolveService("250.1.1." + ToString(i));
while (num_addrs < 64) { // Magic number! 250.1.1.1 - 250.1.1.64 do not collide with deterministic key = 1
CService addr = ResolveService("250.1.1." + ToString(++num_addrs));
BOOST_CHECK(addrman.Add(CAddress(addr, NODE_NONE), source)); BOOST_CHECK(addrman.Add(CAddress(addr, NODE_NONE), source));
addrman.Good(CAddress(addr, NODE_NONE)); addrman.Good(CAddress(addr, NODE_NONE));
//Test: No collision in tried table yet. //Test: No collision in tried table yet.
BOOST_CHECK_EQUAL(addrman.size(), i); BOOST_CHECK_EQUAL(addrman.size(), num_addrs);
} }
//Test: tried table collision! //Test: tried table collision!
CService addr1 = ResolveService("250.1.1.80"); CService addr1 = ResolveService("250.1.1." + ToString(++num_addrs));
uint32_t collisions{1};
BOOST_CHECK(addrman.Add(CAddress(addr1, NODE_NONE), source)); BOOST_CHECK(addrman.Add(CAddress(addr1, NODE_NONE), source));
BOOST_CHECK_EQUAL(addrman.size(), 79U); BOOST_CHECK_EQUAL(addrman.size(), num_addrs - collisions);
CService addr2 = ResolveService("250.1.1.81"); CService addr2 = ResolveService("250.1.1." + ToString(++num_addrs));
BOOST_CHECK(addrman.Add(CAddress(addr2, NODE_NONE), source)); BOOST_CHECK(addrman.Add(CAddress(addr2, NODE_NONE), source));
BOOST_CHECK_EQUAL(addrman.size(), 80U); BOOST_CHECK_EQUAL(addrman.size(), num_addrs - collisions);
} }
BOOST_AUTO_TEST_CASE(addrman_find) BOOST_AUTO_TEST_CASE(addrman_find)
@ -861,9 +856,9 @@ BOOST_AUTO_TEST_CASE(addrman_noevict)
{ {
CAddrManTest addrman; CAddrManTest addrman;
// Add twenty two addresses. // Add 35 addresses.
CNetAddr source = ResolveIP("252.2.2.2"); CNetAddr source = ResolveIP("252.2.2.2");
for (unsigned int i = 1; i < 23; i++) { for (unsigned int i = 1; i < 36; i++) {
CService addr = ResolveService("250.1.1."+ToString(i)); CService addr = ResolveService("250.1.1."+ToString(i));
BOOST_CHECK(addrman.Add(CAddress(addr, NODE_NONE), source)); BOOST_CHECK(addrman.Add(CAddress(addr, NODE_NONE), source));
addrman.Good(addr); addrman.Good(addr);
@ -873,20 +868,20 @@ BOOST_AUTO_TEST_CASE(addrman_noevict)
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0"); BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
} }
// Collision between 23 and 19. // Collision between 36 and 19.
CService addr23 = ResolveService("250.1.1.23"); CService addr36 = ResolveService("250.1.1.36");
BOOST_CHECK(addrman.Add(CAddress(addr23, NODE_NONE), source)); BOOST_CHECK(addrman.Add(CAddress(addr36, NODE_NONE), source));
addrman.Good(addr23); addrman.Good(addr36);
BOOST_CHECK(addrman.size() == 23); BOOST_CHECK(addrman.size() == 36);
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "250.1.1.19:0"); BOOST_CHECK_EQUAL(addrman.SelectTriedCollision().ToString(), "250.1.1.19:0");
// 23 should be discarded and 19 not evicted. // 36 should be discarded and 19 not evicted.
addrman.ResolveCollisions(); addrman.ResolveCollisions();
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0"); BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
// Lets create two collisions. // Lets create two collisions.
for (unsigned int i = 24; i < 33; i++) { for (unsigned int i = 37; i < 59; i++) {
CService addr = ResolveService("250.1.1."+ToString(i)); CService addr = ResolveService("250.1.1."+ToString(i));
BOOST_CHECK(addrman.Add(CAddress(addr, NODE_NONE), source)); BOOST_CHECK(addrman.Add(CAddress(addr, NODE_NONE), source));
addrman.Good(addr); addrman.Good(addr);
@ -896,17 +891,17 @@ BOOST_AUTO_TEST_CASE(addrman_noevict)
} }
// Cause a collision. // Cause a collision.
CService addr33 = ResolveService("250.1.1.33"); CService addr59 = ResolveService("250.1.1.59");
BOOST_CHECK(addrman.Add(CAddress(addr33, NODE_NONE), source)); BOOST_CHECK(addrman.Add(CAddress(addr59, NODE_NONE), source));
addrman.Good(addr33); addrman.Good(addr59);
BOOST_CHECK(addrman.size() == 33); BOOST_CHECK(addrman.size() == 59);
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "250.1.1.27:0"); BOOST_CHECK_EQUAL(addrman.SelectTriedCollision().ToString(), "250.1.1.10:0");
// Cause a second collision. // Cause a second collision.
BOOST_CHECK(!addrman.Add(CAddress(addr23, NODE_NONE), source)); BOOST_CHECK(!addrman.Add(CAddress(addr36, NODE_NONE), source));
addrman.Good(addr23); addrman.Good(addr36);
BOOST_CHECK(addrman.size() == 33); BOOST_CHECK(addrman.size() == 59);
BOOST_CHECK(addrman.SelectTriedCollision().ToString() != "[::]:0"); BOOST_CHECK(addrman.SelectTriedCollision().ToString() != "[::]:0");
addrman.ResolveCollisions(); addrman.ResolveCollisions();
@ -922,9 +917,9 @@ BOOST_AUTO_TEST_CASE(addrman_evictionworks)
// Empty addrman should return blank addrman info. // Empty addrman should return blank addrman info.
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0"); BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
// Add twenty two addresses. // Add 35 addresses
CNetAddr source = ResolveIP("252.2.2.2"); CNetAddr source = ResolveIP("252.2.2.2");
for (unsigned int i = 1; i < 23; i++) { for (unsigned int i = 1; i < 36; i++) {
CService addr = ResolveService("250.1.1."+ToString(i)); CService addr = ResolveService("250.1.1."+ToString(i));
BOOST_CHECK(addrman.Add(CAddress(addr, NODE_NONE), source)); BOOST_CHECK(addrman.Add(CAddress(addr, NODE_NONE), source));
addrman.Good(addr); addrman.Good(addr);
@ -934,34 +929,34 @@ BOOST_AUTO_TEST_CASE(addrman_evictionworks)
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0"); BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
} }
// Collision between 23 and 19. // Collision between 36 and 19.
CService addr = ResolveService("250.1.1.23"); CService addr = ResolveService("250.1.1.36");
BOOST_CHECK(addrman.Add(CAddress(addr, NODE_NONE), source)); BOOST_CHECK(addrman.Add(CAddress(addr, NODE_NONE), source));
addrman.Good(addr); addrman.Good(addr);
BOOST_CHECK(addrman.size() == 23); BOOST_CHECK_EQUAL(addrman.size(), 36);
CAddrInfo info = addrman.SelectTriedCollision(); CAddrInfo info = addrman.SelectTriedCollision();
BOOST_CHECK(info.ToString() == "250.1.1.19:0"); BOOST_CHECK_EQUAL(info.ToString(), "250.1.1.19:0");
// Ensure test of address fails, so that it is evicted. // Ensure test of address fails, so that it is evicted.
addrman.SimConnFail(info); addrman.SimConnFail(info);
// Should swap 23 for 19. // Should swap 36 for 19.
addrman.ResolveCollisions(); addrman.ResolveCollisions();
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0"); BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
// If 23 was swapped for 19, then this should cause no collisions. // If 36 was swapped for 19, then this should cause no collisions.
BOOST_CHECK(!addrman.Add(CAddress(addr, NODE_NONE), source)); BOOST_CHECK(!addrman.Add(CAddress(addr, NODE_NONE), source));
addrman.Good(addr); addrman.Good(addr);
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0"); BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
// If we insert 19 is should collide with 23. // If we insert 19 it should collide with 36
CService addr19 = ResolveService("250.1.1.19"); CService addr19 = ResolveService("250.1.1.19");
BOOST_CHECK(!addrman.Add(CAddress(addr19, NODE_NONE), source)); BOOST_CHECK(!addrman.Add(CAddress(addr19, NODE_NONE), source));
addrman.Good(addr19); addrman.Good(addr19);
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "250.1.1.23:0"); BOOST_CHECK_EQUAL(addrman.SelectTriedCollision().ToString(), "250.1.1.36:0");
addrman.ResolveCollisions(); addrman.ResolveCollisions();
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0"); BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");

View File

@ -29,7 +29,8 @@ public:
FuzzedDataProvider& m_fuzzed_data_provider; FuzzedDataProvider& m_fuzzed_data_provider;
explicit CAddrManDeterministic(FuzzedDataProvider& fuzzed_data_provider) explicit CAddrManDeterministic(FuzzedDataProvider& fuzzed_data_provider)
: m_fuzzed_data_provider(fuzzed_data_provider) : CAddrMan(/* deterministic */ true, /* consistency_check_ratio */ 0)
, m_fuzzed_data_provider(fuzzed_data_provider)
{ {
WITH_LOCK(cs, insecure_rand = FastRandomContext{ConsumeUInt256(fuzzed_data_provider)}); WITH_LOCK(cs, insecure_rand = FastRandomContext{ConsumeUInt256(fuzzed_data_provider)});
if (fuzzed_data_provider.ConsumeBool()) { if (fuzzed_data_provider.ConsumeBool()) {

View File

@ -25,7 +25,7 @@ FUZZ_TARGET_INIT(connman, initialize_connman)
{ {
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
SetMockTime(ConsumeTime(fuzzed_data_provider)); SetMockTime(ConsumeTime(fuzzed_data_provider));
CAddrMan addrman; CAddrMan addrman(/* deterministic */ false, /* consistency_check_ratio */ 0);
CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>(), addrman, fuzzed_data_provider.ConsumeBool()}; CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>(), addrman, fuzzed_data_provider.ConsumeBool()};
CNetAddr random_netaddr; CNetAddr random_netaddr;
CNode random_node = ConsumeNode(fuzzed_data_provider); CNode random_node = ConsumeNode(fuzzed_data_provider);

View File

@ -21,6 +21,6 @@ FUZZ_TARGET_INIT(data_stream_addr_man, initialize_data_stream_addr_man)
{ {
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
CDataStream data_stream = ConsumeDataStream(fuzzed_data_provider); CDataStream data_stream = ConsumeDataStream(fuzzed_data_provider);
CAddrMan addr_man; CAddrMan addr_man(/* deterministic */ false, /* consistency_check_ratio */ 0);
CAddrDB::Read(addr_man, data_stream); CAddrDB::Read(addr_man, data_stream);
} }

View File

@ -188,7 +188,7 @@ FUZZ_TARGET_DESERIALIZE(blockmerkleroot, {
BlockMerkleRoot(block, &mutated); BlockMerkleRoot(block, &mutated);
}) })
FUZZ_TARGET_DESERIALIZE(addrman_deserialize, { FUZZ_TARGET_DESERIALIZE(addrman_deserialize, {
CAddrMan am; CAddrMan am(/* deterministic */ false, /* consistency_check_ratio */ 0);
DeserializeFromFuzzingInput(buffer, am); DeserializeFromFuzzingInput(buffer, am);
}) })
FUZZ_TARGET_DESERIALIZE(blockheader_deserialize, { FUZZ_TARGET_DESERIALIZE(blockheader_deserialize, {

View File

@ -34,13 +34,9 @@ class CAddrManSerializationMock : public CAddrMan
public: public:
virtual void Serialize(CDataStream& s) const = 0; virtual void Serialize(CDataStream& s) const = 0;
//! Ensure that bucket placement is always the same for testing purposes. CAddrManSerializationMock()
void MakeDeterministic() : CAddrMan(/* deterministic */ true, /* consistency_check_ratio */ 100)
{ {}
LOCK(cs);
nKey.SetNull();
insecure_rand = FastRandomContext(true);
}
}; };
class CAddrManUncorrupted : public CAddrManSerializationMock class CAddrManUncorrupted : public CAddrManSerializationMock
@ -105,7 +101,6 @@ BOOST_AUTO_TEST_CASE(cnode_listen_port)
BOOST_AUTO_TEST_CASE(caddrdb_read) BOOST_AUTO_TEST_CASE(caddrdb_read)
{ {
CAddrManUncorrupted addrmanUncorrupted; CAddrManUncorrupted addrmanUncorrupted;
addrmanUncorrupted.MakeDeterministic();
CService addr1, addr2, addr3; CService addr1, addr2, addr3;
BOOST_CHECK(Lookup("250.7.1.1", addr1, 8333, false)); BOOST_CHECK(Lookup("250.7.1.1", addr1, 8333, false));
@ -124,7 +119,7 @@ BOOST_AUTO_TEST_CASE(caddrdb_read)
// Test that the de-serialization does not throw an exception. // Test that the de-serialization does not throw an exception.
CDataStream ssPeers1 = AddrmanToStream(addrmanUncorrupted); CDataStream ssPeers1 = AddrmanToStream(addrmanUncorrupted);
bool exceptionThrown = false; bool exceptionThrown = false;
CAddrMan addrman1; CAddrMan addrman1(/* deterministic */ false, /* consistency_check_ratio */ 100);
BOOST_CHECK(addrman1.size() == 0); BOOST_CHECK(addrman1.size() == 0);
try { try {
@ -141,7 +136,7 @@ BOOST_AUTO_TEST_CASE(caddrdb_read)
// Test that CAddrDB::Read creates an addrman with the correct number of addrs. // Test that CAddrDB::Read creates an addrman with the correct number of addrs.
CDataStream ssPeers2 = AddrmanToStream(addrmanUncorrupted); CDataStream ssPeers2 = AddrmanToStream(addrmanUncorrupted);
CAddrMan addrman2; CAddrMan addrman2(/* deterministic */ false, /* consistency_check_ratio */ 100);
BOOST_CHECK(addrman2.size() == 0); BOOST_CHECK(addrman2.size() == 0);
BOOST_CHECK(CAddrDB::Read(addrman2, ssPeers2)); BOOST_CHECK(CAddrDB::Read(addrman2, ssPeers2));
BOOST_CHECK(addrman2.size() == 3); BOOST_CHECK(addrman2.size() == 3);
@ -151,12 +146,11 @@ BOOST_AUTO_TEST_CASE(caddrdb_read)
BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted) BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
{ {
CAddrManCorrupted addrmanCorrupted; CAddrManCorrupted addrmanCorrupted;
addrmanCorrupted.MakeDeterministic();
// Test that the de-serialization of corrupted addrman throws an exception. // Test that the de-serialization of corrupted addrman throws an exception.
CDataStream ssPeers1 = AddrmanToStream(addrmanCorrupted); CDataStream ssPeers1 = AddrmanToStream(addrmanCorrupted);
bool exceptionThrown = false; bool exceptionThrown = false;
CAddrMan addrman1; CAddrMan addrman1(/* deterministic */ false, /* consistency_check_ratio */ 100);
BOOST_CHECK(addrman1.size() == 0); BOOST_CHECK(addrman1.size() == 0);
try { try {
unsigned char pchMsgTmp[4]; unsigned char pchMsgTmp[4];
@ -172,7 +166,7 @@ BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
// Test that CAddrDB::Read leaves addrman in a clean state if de-serialization fails. // Test that CAddrDB::Read leaves addrman in a clean state if de-serialization fails.
CDataStream ssPeers2 = AddrmanToStream(addrmanCorrupted); CDataStream ssPeers2 = AddrmanToStream(addrmanCorrupted);
CAddrMan addrman2; CAddrMan addrman2(/* deterministic */ false, /* consistency_check_ratio */ 100);
BOOST_CHECK(addrman2.size() == 0); BOOST_CHECK(addrman2.size() == 0);
BOOST_CHECK(!CAddrDB::Read(addrman2, ssPeers2)); BOOST_CHECK(!CAddrDB::Read(addrman2, ssPeers2));
BOOST_CHECK(addrman2.size() == 0); BOOST_CHECK(addrman2.size() == 0);

View File

@ -193,7 +193,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", state.ToString())); throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", state.ToString()));
} }
m_node.addrman = std::make_unique<CAddrMan>(); m_node.addrman = std::make_unique<CAddrMan>(/* deterministic */ false, /* consistency_check_ratio */ 0);
m_node.banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME); m_node.banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
m_node.connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman); // Deterministic randomness for tests. m_node.connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman); // Deterministic randomness for tests.
m_node.peerman = PeerManager::make(chainparams, *m_node.connman, *m_node.addrman, m_node.peerman = PeerManager::make(chainparams, *m_node.connman, *m_node.addrman,