17
17
18
18
#include < algorithm>
19
19
#include < limits>
20
+ #include < unordered_set>
20
21
21
22
namespace llmq
22
23
{
@@ -79,8 +80,23 @@ bool CRecoveredSigsDb::HasRecoveredSigForSession(const uint256& signHash)
79
80
80
81
bool CRecoveredSigsDb::HasRecoveredSigForHash (const uint256& hash)
81
82
{
83
+ int64_t t = GetTimeMillis ();
84
+
85
+ {
86
+ LOCK (cs);
87
+ auto it = hasSigForHashCache.find (hash);
88
+ if (it != hasSigForHashCache.end ()) {
89
+ it->second .second = t;
90
+ return it->second .first ;
91
+ }
92
+ }
93
+
82
94
auto k = std::make_tuple (' h' , hash);
83
- return db.Exists (k);
95
+ bool ret = db.Exists (k);
96
+
97
+ LOCK (cs);
98
+ hasSigForHashCache.emplace (hash, std::make_pair (ret, t));
99
+ return ret;
84
100
}
85
101
86
102
bool CRecoveredSigsDb::ReadRecoveredSig (Consensus::LLMQType llmqType, const uint256& id, CRecoveredSig& ret)
@@ -152,13 +168,14 @@ void CRecoveredSigsDb::WriteRecoveredSig(const llmq::CRecoveredSig& recSig)
152
168
LOCK (cs);
153
169
hasSigForIdCache[std::make_pair ((Consensus::LLMQType)recSig.llmqType , recSig.id )] = std::make_pair (true , t);
154
170
hasSigForSessionCache[signHash] = std::make_pair (true , t);
171
+ hasSigForHashCache[recSig.GetHash ()] = std::make_pair (true , t);
155
172
}
156
173
}
157
174
158
- template <typename K>
159
- static void TruncateCacheMap (std::unordered_map<K, std::pair<bool , int64_t >>& m, size_t maxSize, size_t truncateThreshold)
175
+ template <typename K, typename H >
176
+ static void TruncateCacheMap (std::unordered_map<K, std::pair<bool , int64_t >, H >& m, size_t maxSize, size_t truncateThreshold)
160
177
{
161
- typedef typename std::unordered_map<K, std::pair<bool , int64_t >> Map;
178
+ typedef typename std::unordered_map<K, std::pair<bool , int64_t >, H > Map;
162
179
typedef typename Map::iterator Iterator;
163
180
164
181
if (m.size () <= truncateThreshold) {
@@ -237,10 +254,12 @@ void CRecoveredSigsDb::CleanupOldRecoveredSigs(int64_t maxAge)
237
254
238
255
hasSigForIdCache.erase (std::make_pair ((Consensus::LLMQType)recSig.llmqType , recSig.id ));
239
256
hasSigForSessionCache.erase (signHash);
257
+ hasSigForHashCache.erase (recSig.GetHash ());
240
258
}
241
259
242
260
TruncateCacheMap (hasSigForIdCache, MAX_CACHE_SIZE, MAX_CACHE_TRUNCATE_THRESHOLD);
243
261
TruncateCacheMap (hasSigForSessionCache, MAX_CACHE_SIZE, MAX_CACHE_TRUNCATE_THRESHOLD);
262
+ TruncateCacheMap (hasSigForHashCache, MAX_CACHE_SIZE, MAX_CACHE_TRUNCATE_THRESHOLD);
244
263
}
245
264
246
265
for (auto & e : toDelete2) {
@@ -355,18 +374,17 @@ bool CSigningManager::PreVerifyRecoveredSig(NodeId nodeId, const CRecoveredSig&
355
374
356
375
void CSigningManager::CollectPendingRecoveredSigsToVerify (
357
376
size_t maxUniqueSessions,
358
- std::map <NodeId, std::list<CRecoveredSig>>& retSigShares,
359
- std::map <std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr>& retQuorums)
377
+ std::unordered_map <NodeId, std::list<CRecoveredSig>>& retSigShares,
378
+ std::unordered_map <std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher >& retQuorums)
360
379
{
361
380
{
362
381
LOCK (cs);
363
382
if (pendingRecoveredSigs.empty ()) {
364
383
return ;
365
384
}
366
385
367
- std::set<std::pair<NodeId, uint256>> uniqueSignHashes;
368
- llmq::utils::IterateNodesRandom (
369
- pendingRecoveredSigs, [&]() { return uniqueSignHashes.size () < maxUniqueSessions; }, [&](NodeId nodeId, std::list<CRecoveredSig>& ns) {
386
+ std::unordered_set<std::pair<NodeId, uint256>, StaticSaltedHasher> uniqueSignHashes;
387
+ llmq::utils::IterateNodesRandom (pendingRecoveredSigs, [&]() { return uniqueSignHashes.size () < maxUniqueSessions; }, [&](NodeId nodeId, std::list<CRecoveredSig>& ns) {
370
388
if (ns.empty ()) {
371
389
return false ;
372
390
}
@@ -419,8 +437,8 @@ void CSigningManager::CollectPendingRecoveredSigsToVerify(
419
437
420
438
bool CSigningManager::ProcessPendingRecoveredSigs (CConnman& connman)
421
439
{
422
- std::map <NodeId, std::list<CRecoveredSig>> recSigsByNode;
423
- std::map <std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr> quorums;
440
+ std::unordered_map <NodeId, std::list<CRecoveredSig>> recSigsByNode;
441
+ std::unordered_map <std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher > quorums;
424
442
425
443
CollectPendingRecoveredSigsToVerify (32 , recSigsByNode, quorums);
426
444
if (recSigsByNode.empty ()) {
@@ -443,13 +461,13 @@ bool CSigningManager::ProcessPendingRecoveredSigs(CConnman& connman)
443
461
}
444
462
}
445
463
446
- cxxtimer::Timer verifyTimer;
464
+ cxxtimer::Timer verifyTimer ( true ) ;
447
465
batchVerifier.Verify ();
448
466
verifyTimer.stop ();
449
467
450
468
LogPrintf (" llmq" , " CSigningManager::%s -- verified recovered sig(s). count=%d, vt=%d, nodes=%d\n " , __func__, verifyCount, verifyTimer.count (), recSigsByNode.size ());
451
469
452
- std::set <uint256> processed;
470
+ std::unordered_set <uint256, StaticSaltedHasher > processed;
453
471
for (auto & p : recSigsByNode) {
454
472
NodeId nodeId = p.first ;
455
473
auto & v = p.second ;
@@ -494,11 +512,25 @@ void CSigningManager::ProcessRecoveredSig(NodeId nodeId, const CRecoveredSig& re
494
512
signHash.ToString (), recoveredSig.id .ToString (), recoveredSig.msgHash .ToString (), nodeId);
495
513
496
514
if (db.HasRecoveredSigForId (llmqType, recoveredSig.id )) {
497
- // this should really not happen, as each masternode is participating in only one vote,
498
- // even if it's a member of multiple quorums. so a majority is only possible on one quorum and one msgHash per id
499
- LogPrintf (" CSigningManager::%s -- conflicting recoveredSig for id=%s, msgHash=%s\n " , __func__,
500
- recoveredSig.id .ToString (), recoveredSig.msgHash .ToString ());
501
- return ;
515
+ CRecoveredSig otherRecoveredSig;
516
+ if (db.GetRecoveredSigById (llmqType, recoveredSig.id , otherRecoveredSig)) {
517
+ auto otherSignHash = llmq::utils::BuildSignHash (recoveredSig);
518
+ if (signHash != otherSignHash) {
519
+ // this should really not happen, as each masternode is participating in only one vote,
520
+ // even if it's a member of multiple quorums. so a majority is only possible on one quorum and one msgHash per id
521
+ LogPrintf (" CSigningManager::%s -- conflicting recoveredSig for signHash=%s, id=%s, msgHash=%s, otherSignHash=%s\n " , __func__,
522
+ signHash.ToString (), recoveredSig.id .ToString (), recoveredSig.msgHash .ToString (), otherSignHash.ToString ());
523
+ } else {
524
+ // Looks like we're trying to process a recSig that is already known. This might happen if the same
525
+ // recSig comes in through regular QRECSIG messages and at the same time through some other message
526
+ // which allowed to reconstruct a recSig (e.g. IXLOCK). In this case, just bail out.
527
+ }
528
+ return ;
529
+ } else {
530
+ // This case is very unlikely. It can only happen when cleanup caused this specific recSig to vanish
531
+ // between the HasRecoveredSigForId and GetRecoveredSigById call. If that happens, treat it as if we
532
+ // never had that recSig
533
+ }
502
534
}
503
535
504
536
db.WriteRecoveredSig (recoveredSig);
@@ -552,14 +584,19 @@ bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, const uint
552
584
if (db.HasVotedOnId (llmqType, id)) {
553
585
uint256 prevMsgHash;
554
586
db.GetVoteForId (llmqType, id, prevMsgHash);
555
- LogPrintf (" CSigningManager::%s -- already voted for id=%s and msgHash=%s. Not voting on conflicting msgHash=%s\n " , __func__,
556
- id.ToString (), prevMsgHash.ToString (), msgHash.ToString ());
587
+ if (msgHash != prevMsgHash) {
588
+ LogPrintf (" CSigningManager::%s -- already voted for id=%s and msgHash=%s. Not voting on conflicting msgHash=%s\n " , __func__,
589
+ id.ToString (), prevMsgHash.ToString (), msgHash.ToString ());
590
+ } else {
591
+ LogPrintf (" CSigningManager::%s -- already voted for id=%s and msgHash=%s. Not voting again.\n " , __func__,
592
+ id.ToString (), prevMsgHash.ToString ());
593
+ }
557
594
return false ;
558
595
}
559
596
560
597
if (db.HasRecoveredSigForId (llmqType, id)) {
561
598
// no need to sign it if we already have a recovered sig
562
- return false ;
599
+ return true ;
563
600
}
564
601
db.WriteVoteForId (llmqType, id, msgHash);
565
602
}
0 commit comments