Skip to content

Commit 282ca7d

Browse files
perf: improve signing latency by collecting lazy signatures under lock
1 parent f170aed commit 282ca7d

1 file changed

Lines changed: 36 additions & 17 deletions

File tree

src/llmq/signing_shares.cpp

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -768,8 +768,11 @@ void CSigSharesManager::TryRecoverSig(PeerManager& peerman, const CQuorumCPtr& q
768768
return;
769769
}
770770

771-
std::vector<CBLSSignature> sigSharesForRecovery;
771+
// Collect lazy signatures (cheap copy) under lock, then materialize outside lock
772+
std::vector<CBLSLazySignature> lazySignatures;
772773
std::vector<CBLSId> idsForRecovery;
774+
bool isSingleNode = false;
775+
773776
{
774777
LOCK(cs);
775778

@@ -788,28 +791,44 @@ void CSigSharesManager::TryRecoverSig(PeerManager& peerman, const CQuorumCPtr& q
788791
return;
789792
}
790793
const auto& sigShare = sigSharesForSignHash->begin()->second;
791-
CBLSSignature recoveredSig = sigShare.sigShare.Get();
794+
// Copy the lazy signature (cheap), materialize later outside lock
795+
lazySignatures.emplace_back(sigShare.sigShare);
796+
isSingleNode = true;
792797
LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- recover single-node signature. id=%s, msgHash=%s\n",
793798
__func__, id.ToString(), msgHash.ToString());
799+
} else {
800+
// Collect lazy signatures and IDs under lock (cheap operations)
801+
lazySignatures.reserve((size_t) quorum->params.threshold);
802+
idsForRecovery.reserve((size_t) quorum->params.threshold);
803+
for (auto it = sigSharesForSignHash->begin();
804+
it != sigSharesForSignHash->end() && lazySignatures.size() < size_t(quorum->params.threshold);
805+
++it) {
806+
const auto& sigShare = it->second;
807+
lazySignatures.emplace_back(sigShare.sigShare); // Cheap copy of lazy wrapper
808+
idsForRecovery.emplace_back(quorum->members[sigShare.getQuorumMember()]->proTxHash);
809+
}
794810

795-
auto rs = std::make_shared<CRecoveredSig>(quorum->params.type, quorum->qc->quorumHash, id, msgHash,
796-
recoveredSig);
797-
sigman.ProcessRecoveredSig(rs, peerman);
798-
return; // end of single-quorum processing
811+
// check if we can recover the final signature
812+
if (lazySignatures.size() < size_t(quorum->params.threshold)) {
813+
return;
814+
}
799815
}
816+
} // Release lock before expensive materialization
800817

801-
sigSharesForRecovery.reserve((size_t) quorum->params.threshold);
802-
idsForRecovery.reserve((size_t) quorum->params.threshold);
803-
for (auto it = sigSharesForSignHash->begin(); it != sigSharesForSignHash->end() && sigSharesForRecovery.size() < size_t(quorum->params.threshold); ++it) {
804-
const auto& sigShare = it->second;
805-
sigSharesForRecovery.emplace_back(sigShare.sigShare.Get());
806-
idsForRecovery.emplace_back(quorum->members[sigShare.getQuorumMember()]->proTxHash);
807-
}
818+
// Materialize signatures outside the critical section (expensive BLS operations)
819+
if (isSingleNode) {
820+
CBLSSignature recoveredSig = lazySignatures[0].Get();
821+
auto rs = std::make_shared<CRecoveredSig>(quorum->params.type, quorum->qc->quorumHash, id, msgHash,
822+
recoveredSig);
823+
sigman.ProcessRecoveredSig(rs, peerman);
824+
return; // end of single-quorum processing
825+
}
808826

809-
// check if we can recover the final signature
810-
if (sigSharesForRecovery.size() < size_t(quorum->params.threshold)) {
811-
return;
812-
}
827+
// Multi-node case: materialize all signatures
828+
std::vector<CBLSSignature> sigSharesForRecovery;
829+
sigSharesForRecovery.reserve(lazySignatures.size());
830+
for (const auto& lazySig : lazySignatures) {
831+
sigSharesForRecovery.emplace_back(lazySig.Get()); // Expensive, but outside lock
813832
}
814833

815834
// now recover it

0 commit comments

Comments
 (0)