-
Notifications
You must be signed in to change notification settings - Fork 1.2k
perf: check quorum activity before materializing the quorum on QSIGREC #7531
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -366,14 +366,14 @@ bool CSigningManager::GetRecoveredSigForGetData(const uint256& hash, CRecoveredS | |||||||||||||||||||||||||||||||||||||||||
| void CSigningManager::VerifyAndProcessRecoveredSig(NodeId from, std::shared_ptr<CRecoveredSig> recoveredSig) | ||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||
| auto llmq_type = recoveredSig->getLlmqType(); | ||||||||||||||||||||||||||||||||||||||||||
| auto quorum = qman.GetQuorum(llmq_type, recoveredSig->getQuorumHash()); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| if (!quorum) { | ||||||||||||||||||||||||||||||||||||||||||
| LogPrint(BCLog::LLMQ, "CSigningManager::%s -- quorum %s not found\n", __func__, | ||||||||||||||||||||||||||||||||||||||||||
| recoveredSig->getQuorumHash().ToString()); | ||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| if (!IsQuorumActive(llmq_type, qman, quorum->qc->quorumHash)) { | ||||||||||||||||||||||||||||||||||||||||||
| const uint256& quorum_hash = recoveredSig->getQuorumHash(); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| // Cheap gates first. IsQuorumActive only scans the small cached set of recent | ||||||||||||||||||||||||||||||||||||||||||
| // quorums (keepOldConnections). GetQuorum, by contrast, rebuilds arbitrary | ||||||||||||||||||||||||||||||||||||||||||
| // historical mined commitments (DMN list replay + member selection) on a cache | ||||||||||||||||||||||||||||||||||||||||||
| // miss — do not let an unsolicited QSIGREC force that work for inactive hashes. | ||||||||||||||||||||||||||||||||||||||||||
| // Caller (NetSigning) has already rejected unknown llmq types. | ||||||||||||||||||||||||||||||||||||||||||
| if (!IsQuorumActive(llmq_type, qman, quorum_hash)) { | ||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -383,6 +383,17 @@ void CSigningManager::VerifyAndProcessRecoveredSig(NodeId from, std::shared_ptr< | |||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| // Once IsQuorumActive has passed, quorumHash is one of the few quorums ScanQuorums | ||||||||||||||||||||||||||||||||||||||||||
| // just materialised and cached, so this is a cache hit rather than a rebuild. | ||||||||||||||||||||||||||||||||||||||||||
| auto quorum = qman.GetQuorum(llmq_type, quorum_hash); | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
371
to
+388
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💬 Nitpick: Comments overstate ScanQuorums/GetQuorum caching guarantee The new comments state that IsQuorumActive "only scans the small cached set of recent quorums" and that once it passes, the subsequent GetQuorum call is "a cache hit rather than a rebuild." This isn't quite accurate: ScanQuorums (called by IsQuorumActive) does more than scan a cache — on a scanQuorumsCache miss it calls GetMinedCommitmentsUntilBlock/GetMinedCommitmentsIndexedUntilBlock and materializes up to keepOldConnections quorums via GetQuorum/BuildQuorumFromCommitment. Also, scanQuorumsCache and mapQuorumsCache are separate LRU caches (the former in quorumsman.h keyed by block hash and holding CQuorumCPtr vectors, the latter keyed by quorum hash and holding CQuorumPtr): when ScanQuorums returns a hit from scanQuorumsCache without touching mapQuorumsCache, the quorums it returns may have already aged out of mapQuorumsCache's LRU. The subsequent GetQuorum call would then rebuild via BuildQuorumFromCommitment rather than hitting the cache. This doesn't break the optimization's safety property — the rebuild in that fallback case is still bounded to one of the last few active quorums, not an attacker-chosen historical one — but the comments should describe a bounded-cost guarantee rather than an unconditional cache-hit guarantee.
Suggested change
source: ['codex'] |
||||||||||||||||||||||||||||||||||||||||||
| if (!quorum) { | ||||||||||||||||||||||||||||||||||||||||||
| // Reported active by ScanQuorums but no longer materializable (e.g. reorg). | ||||||||||||||||||||||||||||||||||||||||||
| // Not peer-controlled once the hash is restricted to the active set, so no score. | ||||||||||||||||||||||||||||||||||||||||||
| LogPrint(BCLog::LLMQ, "CSigningManager::%s -- quorum %s not found\n", __func__, | ||||||||||||||||||||||||||||||||||||||||||
| quorum_hash.ToString()); | ||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| LogPrint(BCLog::LLMQ, "CSigningManager::%s -- signHash=%s, id=%s, msgHash=%s, node=%d\n", __func__, | ||||||||||||||||||||||||||||||||||||||||||
| recoveredSig->buildSignHash().ToString(), recoveredSig->getId().ToString(), recoveredSig->getMsgHash().ToString(), from); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Correct the cache behavior in this rationale.
IsQuorumActivecallsScanQuorums. On a scan-cache miss,ScanQuorumsmaterializes recent quorums throughGetQuorum; it does not only scan an existing cache. State that the check is bounded to recentkeepOldConnectionsquorums. This preserves the actual performance property: it avoids reconstruction of the arbitrary historical quorum supplied by the peer.As per coding guidelines, reserve C++ comments for non-obvious rationale.
Proposed fix
📝 Committable suggestion
🤖 Prompt for AI Agents
Source: Coding guidelines