Skip to content

Commit a4d7854

Browse files
committed
[addrman] Make addrman consistency checks a runtime option
Currently addrman consistency checks are a compile time option, and are not enabled in our CI. It's unlikely anyone is running these consistency checks. Make them a runtime option instead, where users can enable addrman consistency checks every n operations (similar to mempool tests). Update the addrman unit tests to do internal consistency checks every 100 operations (checking on every operations causes the test runtime to increase by several seconds). Also assert on a failed addrman consistency check to terminate program execution.
1 parent 10aac24 commit a4d7854

File tree

11 files changed

+37
-25
lines changed

11 files changed

+37
-25
lines changed

src/addrman.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -433,9 +433,12 @@ CAddrInfo CAddrMan::Select_(bool newOnly) const
433433

434434
int CAddrMan::Check_() const
435435
{
436-
#ifdef DEBUG_ADDRMAN
437436
AssertLockHeld(cs);
438437

438+
// Run consistency checks 1 in m_consistency_check_ratio times if enabled
439+
if (m_consistency_check_ratio == 0) return 0;
440+
if (insecure_rand.randrange(m_consistency_check_ratio) >= 1) return 0;
441+
439442
std::unordered_set<int> setTried;
440443
std::unordered_map<int, int> mapNew;
441444

@@ -514,7 +517,6 @@ int CAddrMan::Check_() const
514517
if (nKey.IsNull())
515518
return -16;
516519

517-
#endif // DEBUG_ADDRMAN
518520
return 0;
519521
}
520522

src/addrman.h

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
#include <unordered_map>
2727
#include <vector>
2828

29+
/** Default for -checkaddrman */
30+
static constexpr int32_t DEFAULT_ADDRMAN_CONSISTENCY_CHECKS{0};
31+
2932
/**
3033
* Extended statistics about a CAddress
3134
*/
@@ -124,8 +127,8 @@ class CAddrInfo : public CAddress
124127
* attempt was unsuccessful.
125128
* * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not
126129
* be observable by adversaries.
127-
* * Several indexes are kept for high performance. Defining DEBUG_ADDRMAN will introduce frequent (and expensive)
128-
* consistency checks for the entire data structure.
130+
* * Several indexes are kept for high performance. Setting m_consistency_check_ratio with the -checkaddrman
131+
* configuration option will introduce (expensive) consistency checks for the entire data structure.
129132
*/
130133

131134
//! total number of buckets for tried addresses
@@ -493,8 +496,9 @@ class CAddrMan
493496
mapAddr.clear();
494497
}
495498

496-
explicit CAddrMan(bool deterministic)
497-
: insecure_rand{deterministic}
499+
explicit CAddrMan(bool deterministic, int32_t consistency_check_ratio)
500+
: insecure_rand{deterministic},
501+
m_consistency_check_ratio{consistency_check_ratio}
498502
{
499503
Clear();
500504
if (deterministic) nKey = uint256{1};
@@ -700,6 +704,9 @@ class CAddrMan
700704
//! Holds addrs inserted into tried table that collide with existing entries. Test-before-evict discipline used to resolve these collisions.
701705
std::set<int> m_tried_collisions;
702706

707+
/** Perform consistency checks every m_consistency_check_ratio operations (if non-zero). */
708+
const int32_t m_consistency_check_ratio;
709+
703710
//! Find an entry.
704711
CAddrInfo* Find(const CNetAddr& addr, int *pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
705712

@@ -737,13 +744,14 @@ class CAddrMan
737744
CAddrInfo SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs);
738745

739746
//! Consistency check
740-
void Check() const
741-
EXCLUSIVE_LOCKS_REQUIRED(cs)
747+
void Check() const EXCLUSIVE_LOCKS_REQUIRED(cs)
742748
{
743749
AssertLockHeld(cs);
750+
744751
const int err = Check_();
745752
if (err) {
746753
LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
754+
assert(false);
747755
}
748756
}
749757

src/bench/addrman.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ static void AddrManAdd(benchmark::Bench& bench)
7272
{
7373
CreateAddresses();
7474

75-
CAddrMan addrman(/* deterministic */ false);
75+
CAddrMan addrman(/* deterministic */ false, /* consistency_check_ratio */ 0);
7676

7777
bench.run([&] {
7878
AddAddressesToAddrMan(addrman);
@@ -82,7 +82,7 @@ static void AddrManAdd(benchmark::Bench& bench)
8282

8383
static void AddrManSelect(benchmark::Bench& bench)
8484
{
85-
CAddrMan addrman(/* deterministic */ false);
85+
CAddrMan addrman(/* deterministic */ false, /* consistency_check_ratio */ 0);
8686

8787
FillAddrMan(addrman);
8888

@@ -94,7 +94,7 @@ static void AddrManSelect(benchmark::Bench& bench)
9494

9595
static void AddrManGetAddr(benchmark::Bench& bench)
9696
{
97-
CAddrMan addrman(/* deterministic */ false);
97+
CAddrMan addrman(/* deterministic */ false, /* consistency_check_ratio */ 0);
9898

9999
FillAddrMan(addrman);
100100

@@ -116,7 +116,7 @@ static void AddrManGood(benchmark::Bench& bench)
116116

117117
std::vector<std::unique_ptr<CAddrMan>> addrmans(addrman_count);
118118
for (size_t i{0}; i < addrman_count; ++i) {
119-
addrmans[i] = std::make_unique<CAddrMan>(/* deterministic */ false);
119+
addrmans[i] = std::make_unique<CAddrMan>(/* deterministic */ false, /* consistency_check_ratio */ 0);
120120
FillAddrMan(*addrmans[i]);
121121
}
122122

src/init.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,8 @@ void SetupServerArgs(ArgsManager& argsman)
501501
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);
502502
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);
503503
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);
504-
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);
504+
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);
505+
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);
505506
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);
506507
argsman.AddArg("-deprecatedrpc=<method>", "Allows deprecated RPC method(s) to be used", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
507508
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)
11641165
const bool ignores_incoming_txs{args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)};
11651166

11661167
assert(!node.addrman);
1167-
node.addrman = std::make_unique<CAddrMan>(/* deterministic */ false);
1168+
auto check_addrman = std::clamp<int32_t>(args.GetArg("-checkaddrman", DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), 0, 1000000);
1169+
node.addrman = std::make_unique<CAddrMan>(/* deterministic */ false, /* consistency_check_ratio */ check_addrman);
11681170
assert(!node.banman);
11691171
node.banman = std::make_unique<BanMan>(gArgs.GetDataDirNet() / "banlist", &uiInterface, args.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME));
11701172
assert(!node.connman);

src/test/addrman_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class CAddrManTest : public CAddrMan
2222
public:
2323
explicit CAddrManTest(bool makeDeterministic = true,
2424
std::vector<bool> asmap = std::vector<bool>())
25-
: CAddrMan(makeDeterministic)
25+
: CAddrMan(makeDeterministic, /* consistency_check_ratio */ 100)
2626
{
2727
deterministic = makeDeterministic;
2828
m_asmap = asmap;

src/test/fuzz/addrman.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class CAddrManDeterministic : public CAddrMan
2929
FuzzedDataProvider& m_fuzzed_data_provider;
3030

3131
explicit CAddrManDeterministic(FuzzedDataProvider& fuzzed_data_provider)
32-
: CAddrMan(/* deterministic */ true)
32+
: CAddrMan(/* deterministic */ true, /* consistency_check_ratio */ 0)
3333
, m_fuzzed_data_provider(fuzzed_data_provider)
3434
{
3535
WITH_LOCK(cs, insecure_rand = FastRandomContext{ConsumeUInt256(fuzzed_data_provider)});

src/test/fuzz/connman.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ FUZZ_TARGET_INIT(connman, initialize_connman)
2525
{
2626
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
2727
SetMockTime(ConsumeTime(fuzzed_data_provider));
28-
CAddrMan addrman(/* deterministic */ false);
28+
CAddrMan addrman(/* deterministic */ false, /* consistency_check_ratio */ 0);
2929
CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>(), addrman, fuzzed_data_provider.ConsumeBool()};
3030
CNetAddr random_netaddr;
3131
CNode random_node = ConsumeNode(fuzzed_data_provider);

src/test/fuzz/data_stream.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@ FUZZ_TARGET_INIT(data_stream_addr_man, initialize_data_stream_addr_man)
2121
{
2222
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
2323
CDataStream data_stream = ConsumeDataStream(fuzzed_data_provider);
24-
CAddrMan addr_man(/* deterministic */ false);
24+
CAddrMan addr_man(/* deterministic */ false, /* consistency_check_ratio */ 0);
2525
CAddrDB::Read(addr_man, data_stream);
2626
}

src/test/fuzz/deserialize.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ FUZZ_TARGET_DESERIALIZE(blockmerkleroot, {
188188
BlockMerkleRoot(block, &mutated);
189189
})
190190
FUZZ_TARGET_DESERIALIZE(addrman_deserialize, {
191-
CAddrMan am(/* deterministic */ false);
191+
CAddrMan am(/* deterministic */ false, /* consistency_check_ratio */ 0);
192192
DeserializeFromFuzzingInput(buffer, am);
193193
})
194194
FUZZ_TARGET_DESERIALIZE(blockheader_deserialize, {

src/test/net_tests.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class CAddrManSerializationMock : public CAddrMan
3535
virtual void Serialize(CDataStream& s) const = 0;
3636

3737
CAddrManSerializationMock()
38-
: CAddrMan(/* deterministic */ true)
38+
: CAddrMan(/* deterministic */ true, /* consistency_check_ratio */ 100)
3939
{}
4040
};
4141

@@ -119,7 +119,7 @@ BOOST_AUTO_TEST_CASE(caddrdb_read)
119119
// Test that the de-serialization does not throw an exception.
120120
CDataStream ssPeers1 = AddrmanToStream(addrmanUncorrupted);
121121
bool exceptionThrown = false;
122-
CAddrMan addrman1(/* deterministic */ false);
122+
CAddrMan addrman1(/* deterministic */ false, /* consistency_check_ratio */ 100);
123123

124124
BOOST_CHECK(addrman1.size() == 0);
125125
try {
@@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE(caddrdb_read)
136136
// Test that CAddrDB::Read creates an addrman with the correct number of addrs.
137137
CDataStream ssPeers2 = AddrmanToStream(addrmanUncorrupted);
138138

139-
CAddrMan addrman2(/* deterministic */ false);
139+
CAddrMan addrman2(/* deterministic */ false, /* consistency_check_ratio */ 100);
140140
BOOST_CHECK(addrman2.size() == 0);
141141
BOOST_CHECK(CAddrDB::Read(addrman2, ssPeers2));
142142
BOOST_CHECK(addrman2.size() == 3);
@@ -150,7 +150,7 @@ BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
150150
// Test that the de-serialization of corrupted addrman throws an exception.
151151
CDataStream ssPeers1 = AddrmanToStream(addrmanCorrupted);
152152
bool exceptionThrown = false;
153-
CAddrMan addrman1(/* deterministic */ false);
153+
CAddrMan addrman1(/* deterministic */ false, /* consistency_check_ratio */ 100);
154154
BOOST_CHECK(addrman1.size() == 0);
155155
try {
156156
unsigned char pchMsgTmp[4];
@@ -166,7 +166,7 @@ BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
166166
// Test that CAddrDB::Read leaves addrman in a clean state if de-serialization fails.
167167
CDataStream ssPeers2 = AddrmanToStream(addrmanCorrupted);
168168

169-
CAddrMan addrman2(/* deterministic */ false);
169+
CAddrMan addrman2(/* deterministic */ false, /* consistency_check_ratio */ 100);
170170
BOOST_CHECK(addrman2.size() == 0);
171171
BOOST_CHECK(!CAddrDB::Read(addrman2, ssPeers2));
172172
BOOST_CHECK(addrman2.size() == 0);

0 commit comments

Comments
 (0)