Skip to content

Commit 56f40c3

Browse files
fix: make SelectQuorumForSigning resolve strictly via active chain under cs_main
Always derive pindexStart from the authoritative active chain (with SIGN_HEIGHT_OFFSET) for both signing and verification. This removes cached-view variability that led to missed ChainLocks in rotation tests, while keeping other paths cs_main-free.
1 parent 970ba10 commit 56f40c3

File tree

1 file changed

+10
-47
lines changed

1 file changed

+10
-47
lines changed

src/llmq/quorums.cpp

Lines changed: 10 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,54 +1325,17 @@ CQuorumCPtr SelectQuorumForSigning(const Consensus::LLMQParams& llmq_params, con
13251325
size_t poolSize = llmq_params.signingActiveQuorumCount;
13261326

13271327
CBlockIndex* pindexStart;
1328-
// If caller provided an explicit signHeight, always resolve relative to the active chain
1329-
// to guarantee correctness during rapid tip changes and rotations.
1330-
if (signHeight != -1) {
1331-
LOCK(::cs_main);
1332-
int startBlockHeight = signHeight - signOffset;
1333-
if (startBlockHeight > active_chain.Height() || startBlockHeight < 0) {
1334-
return {};
1335-
}
1336-
pindexStart = active_chain[startBlockHeight];
1337-
} else {
1338-
// No explicit height: prefer cs_main-free path via active chain view
1339-
auto view = qman.GetActiveChainView();
1340-
if (view.tip) {
1341-
signHeight = view.height;
1342-
int startBlockHeight = signHeight - signOffset;
1343-
if (startBlockHeight < 0) {
1344-
return {};
1345-
}
1346-
if (startBlockHeight <= view.height) {
1347-
const CBlockIndex* ancestor = qman.FindAncestorFast(view, startBlockHeight);
1348-
if (!ancestor) {
1349-
// Fallback to cs_main if cache missed (e.g. during reorg/initialization)
1350-
LOCK(::cs_main);
1351-
if (startBlockHeight > active_chain.Height()) {
1352-
return {};
1353-
}
1354-
pindexStart = active_chain[startBlockHeight];
1355-
} else {
1356-
pindexStart = const_cast<CBlockIndex*>(ancestor);
1357-
}
1358-
} else {
1359-
// View is behind requested height; fallback to cs_main
1360-
LOCK(::cs_main);
1361-
if (startBlockHeight > active_chain.Height()) {
1362-
return {};
1363-
}
1364-
pindexStart = active_chain[startBlockHeight];
1365-
}
1366-
} else {
1367-
LOCK(::cs_main);
1368-
signHeight = active_chain.Height();
1369-
int startBlockHeight = signHeight - signOffset;
1370-
if (startBlockHeight > active_chain.Height() || startBlockHeight < 0) {
1371-
return {};
1372-
}
1373-
pindexStart = active_chain[startBlockHeight];
1374-
}
1328+
// Resolve strictly relative to the authoritative active chain to avoid any
1329+
// cross-tip inconsistencies during rotations or rapid tip changes.
1330+
LOCK(::cs_main);
1331+
if (signHeight == -1) {
1332+
signHeight = active_chain.Height();
1333+
}
1334+
int startBlockHeight = signHeight - signOffset;
1335+
if (startBlockHeight > active_chain.Height() || startBlockHeight < 0) {
1336+
return {};
13751337
}
1338+
pindexStart = active_chain[startBlockHeight];
13761339

13771340
if (IsQuorumRotationEnabled(llmq_params, pindexStart)) {
13781341
auto quorums = qman.ScanQuorums(llmq_params.type, pindexStart, poolSize);

0 commit comments

Comments
 (0)