Skip to content

Commit 5b2d866

Browse files
author
MarcoFalke
committed
Merge bitcoin/bitcoin#22577: Close minor startup race between main and scheduler threads
703b1e6 Close minor startup race between main and scheduler threads (Larry Ruane) Pull request description: This is a low-priority bug fix. The scheduler thread runs `CheckForStaleTipAndEvictPeers()` every 45 seconds (EXTRA_PEER_CHECK_INTERVAL). If its first run happens before the active chain is set up (`CChain::SetTip()`), `bitcoind` will assert: ``` (...) 2021-07-28T22:16:49Z init message: Loading block index… bitcoind: validation.cpp:4968: CChainState& ChainstateManager::ActiveChainstate() const: Assertion `m_active_chainstate' failed. Aborted (core dumped) ``` I ran into this while using the debugger to investigate an unrelated problem. Single-stepping through threads with a debugger can cause the relative thread execution timing to be very different than usual. I don't think any automated tests are needed for this PR. I'll give reproduction steps in the next PR comment. ACKs for top commit: MarcoFalke: cr ACK 703b1e6 tryphe: tested ACK 703b1e6 0xB10C: ACK 703b1e6 glozow: code review ACK 703b1e6 - it makes sense to me to start peerman's background tasks here, after `chainstate->LoadChainTip()` and `node.connman->Start()` have been called. Tree-SHA512: 9316ad768cba3b171f62e2eb400e3790af66c47d1886d7965edb38d9710fc8c8f8e4fb38232811c9346732ce311d39f740c5c2aaf5f6ca390ddc48c51a8d633b
2 parents 3308c61 + 703b1e6 commit 5b2d866

File tree

5 files changed

+21
-11
lines changed

5 files changed

+21
-11
lines changed

src/init.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1185,7 +1185,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
11851185

11861186
assert(!node.peerman);
11871187
node.peerman = PeerManager::make(chainparams, *node.connman, *node.addrman, node.banman.get(),
1188-
*node.scheduler, chainman, *node.mempool, ignores_incoming_txs);
1188+
chainman, *node.mempool, ignores_incoming_txs);
11891189
RegisterValidationInterface(node.peerman.get());
11901190

11911191
// sanitize comments per BIP-0014, format user agent and check total size
@@ -1794,6 +1794,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
17941794
banman->DumpBanlist();
17951795
}, DUMP_BANS_INTERVAL);
17961796

1797+
if (node.peerman) node.peerman->StartScheduledTasks(*node.scheduler);
1798+
17971799
#if HAVE_SYSTEM
17981800
StartupNotify(args);
17991801
#endif

src/net_processing.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ class PeerManagerImpl final : public PeerManager
292292
{
293293
public:
294294
PeerManagerImpl(const CChainParams& chainparams, CConnman& connman, CAddrMan& addrman,
295-
BanMan* banman, CScheduler& scheduler, ChainstateManager& chainman,
295+
BanMan* banman, ChainstateManager& chainman,
296296
CTxMemPool& pool, bool ignore_incoming_txs);
297297

298298
/** Overridden from CValidationInterface. */
@@ -309,6 +309,7 @@ class PeerManagerImpl final : public PeerManager
309309
bool SendMessages(CNode* pto) override EXCLUSIVE_LOCKS_REQUIRED(pto->cs_sendProcessing);
310310

311311
/** Implement PeerManager */
312+
void StartScheduledTasks(CScheduler& scheduler) override;
312313
void CheckForStaleTipAndEvictPeers() override;
313314
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const override;
314315
bool IgnoresIncomingTxs() override { return m_ignore_incoming_txs; }
@@ -1419,14 +1420,14 @@ bool PeerManagerImpl::BlockRequestAllowed(const CBlockIndex* pindex)
14191420
}
14201421

14211422
std::unique_ptr<PeerManager> PeerManager::make(const CChainParams& chainparams, CConnman& connman, CAddrMan& addrman,
1422-
BanMan* banman, CScheduler& scheduler, ChainstateManager& chainman,
1423+
BanMan* banman, ChainstateManager& chainman,
14231424
CTxMemPool& pool, bool ignore_incoming_txs)
14241425
{
1425-
return std::make_unique<PeerManagerImpl>(chainparams, connman, addrman, banman, scheduler, chainman, pool, ignore_incoming_txs);
1426+
return std::make_unique<PeerManagerImpl>(chainparams, connman, addrman, banman, chainman, pool, ignore_incoming_txs);
14261427
}
14271428

14281429
PeerManagerImpl::PeerManagerImpl(const CChainParams& chainparams, CConnman& connman, CAddrMan& addrman,
1429-
BanMan* banman, CScheduler& scheduler, ChainstateManager& chainman,
1430+
BanMan* banman, ChainstateManager& chainman,
14301431
CTxMemPool& pool, bool ignore_incoming_txs)
14311432
: m_chainparams(chainparams),
14321433
m_connman(connman),
@@ -1435,6 +1436,10 @@ PeerManagerImpl::PeerManagerImpl(const CChainParams& chainparams, CConnman& conn
14351436
m_chainman(chainman),
14361437
m_mempool(pool),
14371438
m_ignore_incoming_txs(ignore_incoming_txs)
1439+
{
1440+
}
1441+
1442+
void PeerManagerImpl::StartScheduledTasks(CScheduler& scheduler)
14381443
{
14391444
// Stale tip checking and peer eviction are on two different timers, but we
14401445
// don't want them to get out of sync due to drift in the scheduler, so we

src/net_processing.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,13 @@ class PeerManager : public CValidationInterface, public NetEventsInterface
3838
{
3939
public:
4040
static std::unique_ptr<PeerManager> make(const CChainParams& chainparams, CConnman& connman, CAddrMan& addrman,
41-
BanMan* banman, CScheduler& scheduler, ChainstateManager& chainman,
41+
BanMan* banman, ChainstateManager& chainman,
4242
CTxMemPool& pool, bool ignore_incoming_txs);
4343
virtual ~PeerManager() { }
4444

45+
/** Begin running background tasks, should only be called once */
46+
virtual void StartScheduledTasks(CScheduler& scheduler) = 0;
47+
4548
/** Get statistics from node state */
4649
virtual bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const = 0;
4750

src/test/denialofservice_tests.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
5353
const CChainParams& chainparams = Params();
5454
auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman);
5555
auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, nullptr,
56-
*m_node.scheduler, *m_node.chainman, *m_node.mempool, false);
56+
*m_node.chainman, *m_node.mempool, false);
5757

5858
// Mock an outbound peer
5959
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
@@ -121,7 +121,7 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
121121
const CChainParams& chainparams = Params();
122122
auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman);
123123
auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, nullptr,
124-
*m_node.scheduler, *m_node.chainman, *m_node.mempool, false);
124+
*m_node.chainman, *m_node.mempool, false);
125125

126126
constexpr int max_outbound_full_relay = MAX_OUTBOUND_FULL_RELAY_CONNECTIONS;
127127
CConnman::Options options;
@@ -194,7 +194,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
194194
auto banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
195195
auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman);
196196
auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, banman.get(),
197-
*m_node.scheduler, *m_node.chainman, *m_node.mempool, false);
197+
*m_node.chainman, *m_node.mempool, false);
198198

199199
CNetAddr tor_netaddr;
200200
BOOST_REQUIRE(
@@ -288,7 +288,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
288288
auto banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
289289
auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman);
290290
auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, banman.get(),
291-
*m_node.scheduler, *m_node.chainman, *m_node.mempool, false);
291+
*m_node.chainman, *m_node.mempool, false);
292292

293293
banman->ClearBanned();
294294
int64_t nStartTime = GetTime();

src/test/util/setup_common.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
197197
m_node.banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
198198
m_node.connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman); // Deterministic randomness for tests.
199199
m_node.peerman = PeerManager::make(chainparams, *m_node.connman, *m_node.addrman,
200-
m_node.banman.get(), *m_node.scheduler, *m_node.chainman,
200+
m_node.banman.get(), *m_node.chainman,
201201
*m_node.mempool, false);
202202
{
203203
CConnman::Options options;

0 commit comments

Comments
 (0)