@@ -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