Skip to content

Commit 5e79dbe

Browse files
UdjinM6claude
andcommitted
fix: initialize quorum connections at startup on idle chains
After PR dashpay#7063 (commit 1360d9d), CQuorumManager::UpdatedBlockTip was moved from CDSNotificationInterface::UpdatedBlockTip (which is called directly at startup via InitializeCurrentBlockTip) to the ActiveContext/ObserverContext CValidationInterface subscribers. These subscribers only receive UpdatedBlockTip via GetMainSignals() broadcast, which is never triggered at startup on idle chains — ActivateBestChain early-returns when pindexMostWork == m_chain.Tip(). This means that after a full restart with no new blocks: - QuorumObserver::UpdatedBlockTip never fires - CheckQuorumConnections is never called - Quorum connections are never re-established - MNs cannot exchange signing shares - InstantSend and ChainLock signing fails Fix by adding InitializeCurrentBlockTip() to ActiveContext and ObserverContext, called from the loadblk thread right after CDSNotificationInterface::InitializeCurrentBlockTip(). This method also calls the new QuorumObserver::InitializeQuorumConnections(), which bypasses the IsBlockchainSynced() guard (mnsync is not yet complete at that point in the startup sequence). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1d212a1 commit 5e79dbe

7 files changed

Lines changed: 35 additions & 0 deletions

File tree

src/active/context.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,14 @@ void ActiveContext::SetCJServer(gsl::not_null<CCoinJoinServer*> cj_server)
9797
m_cj_server = cj_server;
9898
}
9999

100+
void ActiveContext::InitializeCurrentBlockTip(const CBlockIndex* tip, bool ibd)
101+
{
102+
UpdatedBlockTip(tip, nullptr, ibd);
103+
if (tip) {
104+
qman_handler->InitializeQuorumConnections(tip);
105+
}
106+
}
107+
100108
void ActiveContext::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload)
101109
{
102110
if (fInitialDownload || pindexNew == pindexFork) // In IBD or blocks were disconnected without any new ones

src/active/context.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ struct ActiveContext final : public CValidationInterface {
7474

7575
void Start(CConnman& connman, PeerManager& peerman, int16_t worker_count);
7676
void Stop();
77+
void InitializeCurrentBlockTip(const CBlockIndex* tip, bool ibd);
7778

7879
CCoinJoinServer& GetCJServer() const;
7980
void SetCJServer(gsl::not_null<CCoinJoinServer*> cj_server);

src/init.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2417,6 +2417,15 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
24172417
// but don't call it directly to prevent triggering of other listeners like zmq etc.
24182418
// GetMainSignals().UpdatedBlockTip(::ChainActive().Tip());
24192419
g_ds_notification_interface->InitializeCurrentBlockTip();
2420+
{
2421+
const CBlockIndex* tip = WITH_LOCK(::cs_main, return chainman.ActiveTip());
2422+
const bool ibd = chainman.ActiveChainstate().IsInitialBlockDownload();
2423+
if (node.active_ctx) {
2424+
node.active_ctx->InitializeCurrentBlockTip(tip, ibd);
2425+
} else if (node.observer_ctx) {
2426+
node.observer_ctx->InitializeCurrentBlockTip(tip, ibd);
2427+
}
2428+
}
24202429

24212430
{
24222431
// Get all UTXOs for each MN collateral in one go so that we can fill coin cache early

src/llmq/observer/context.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ void ObserverContext::Stop()
4747
qman_handler->Stop();
4848
}
4949

50+
void ObserverContext::InitializeCurrentBlockTip(const CBlockIndex* tip, bool ibd)
51+
{
52+
UpdatedBlockTip(tip, nullptr, ibd);
53+
if (tip) {
54+
qman_handler->InitializeQuorumConnections(tip);
55+
}
56+
}
57+
5058
void ObserverContext::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload)
5159
{
5260
if (fInitialDownload || pindexNew == pindexFork) // In IBD or blocks were disconnected without any new ones

src/llmq/observer/context.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ struct ObserverContext final : public CValidationInterface {
4949

5050
void Start(int16_t worker_count);
5151
void Stop();
52+
void InitializeCurrentBlockTip(const CBlockIndex* tip, bool ibd);
5253

5354
protected:
5455
// CValidationInterface

src/llmq/observer/quorums.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@ void QuorumObserver::Stop()
5959
workerPool.stop(true);
6060
}
6161

62+
void QuorumObserver::InitializeQuorumConnections(gsl::not_null<const CBlockIndex*> pindexNew) const
63+
{
64+
for (const auto& params : Params().GetConsensus().llmqs) {
65+
CheckQuorumConnections(params, pindexNew);
66+
}
67+
}
68+
6269
void QuorumObserver::UpdatedBlockTip(const CBlockIndex* pindexNew, bool fInitialDownload) const
6370
{
6471
if (!pindexNew) return;

src/llmq/observer/quorums.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ class QuorumObserver
9696
void Stop();
9797

9898
void UpdatedBlockTip(const CBlockIndex* pindexNew, bool fInitialDownload) const;
99+
void InitializeQuorumConnections(gsl::not_null<const CBlockIndex*> pindexNew) const;
99100

100101
public:
101102
virtual bool SetQuorumSecretKeyShare(CQuorum& quorum, Span<CBLSSecretKey> skContributions) const;

0 commit comments

Comments
 (0)