Skip to content

Commit 7ccd790

Browse files
codablockpanleone
authored andcommitted
Merge pull request #2725 from codablock/pr_llmq_hashmaps
Add more caching to CRecoveredSigsDb and use salted hashing for externally provided keys
1 parent a0084f5 commit 7ccd790

File tree

4 files changed

+66
-71
lines changed

4 files changed

+66
-71
lines changed

src/llmq/quorums_signing.cpp

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,23 @@ bool CRecoveredSigsDb::HasRecoveredSigForSession(const uint256& signHash)
8080

8181
bool CRecoveredSigsDb::HasRecoveredSigForHash(const uint256& hash)
8282
{
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+
8394
auto k = std::make_tuple('h', hash);
84-
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;
85100
}
86101

87102
bool CRecoveredSigsDb::ReadRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, CRecoveredSig& ret)
@@ -153,13 +168,14 @@ void CRecoveredSigsDb::WriteRecoveredSig(const llmq::CRecoveredSig& recSig)
153168
LOCK(cs);
154169
hasSigForIdCache[std::make_pair((Consensus::LLMQType)recSig.llmqType, recSig.id)] = std::make_pair(true, t);
155170
hasSigForSessionCache[signHash] = std::make_pair(true, t);
171+
hasSigForHashCache[recSig.GetHash()] = std::make_pair(true, t);
156172
}
157173
}
158174

159-
template <typename K>
160-
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)
161177
{
162-
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;
163179
typedef typename Map::iterator Iterator;
164180

165181
if (m.size() <= truncateThreshold) {
@@ -238,10 +254,12 @@ void CRecoveredSigsDb::CleanupOldRecoveredSigs(int64_t maxAge)
238254

239255
hasSigForIdCache.erase(std::make_pair((Consensus::LLMQType)recSig.llmqType, recSig.id));
240256
hasSigForSessionCache.erase(signHash);
257+
hasSigForHashCache.erase(recSig.GetHash());
241258
}
242259

243260
TruncateCacheMap(hasSigForIdCache, MAX_CACHE_SIZE, MAX_CACHE_TRUNCATE_THRESHOLD);
244261
TruncateCacheMap(hasSigForSessionCache, MAX_CACHE_SIZE, MAX_CACHE_TRUNCATE_THRESHOLD);
262+
TruncateCacheMap(hasSigForHashCache, MAX_CACHE_SIZE, MAX_CACHE_TRUNCATE_THRESHOLD);
245263
}
246264

247265
for (auto& e : toDelete2) {
@@ -357,15 +375,15 @@ bool CSigningManager::PreVerifyRecoveredSig(NodeId nodeId, const CRecoveredSig&
357375
void CSigningManager::CollectPendingRecoveredSigsToVerify(
358376
size_t maxUniqueSessions,
359377
std::unordered_map<NodeId, std::list<CRecoveredSig>>& retSigShares,
360-
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr>& retQuorums)
378+
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& retQuorums)
361379
{
362380
{
363381
LOCK(cs);
364382
if (pendingRecoveredSigs.empty()) {
365383
return;
366384
}
367385

368-
std::unordered_set<std::pair<NodeId, uint256>> uniqueSignHashes;
386+
std::unordered_set<std::pair<NodeId, uint256>, StaticSaltedHasher> uniqueSignHashes;
369387
llmq::utils::IterateNodesRandom(pendingRecoveredSigs, [&]() { return uniqueSignHashes.size() < maxUniqueSessions; }, [&](NodeId nodeId, std::list<CRecoveredSig>& ns) {
370388
if (ns.empty()) {
371389
return false;
@@ -420,7 +438,7 @@ void CSigningManager::CollectPendingRecoveredSigsToVerify(
420438
bool CSigningManager::ProcessPendingRecoveredSigs(CConnman& connman)
421439
{
422440
std::unordered_map<NodeId, std::list<CRecoveredSig>> recSigsByNode;
423-
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr> quorums;
441+
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher> quorums;
424442

425443
CollectPendingRecoveredSigsToVerify(32, recSigsByNode, quorums);
426444
if (recSigsByNode.empty()) {
@@ -449,7 +467,7 @@ bool CSigningManager::ProcessPendingRecoveredSigs(CConnman& connman)
449467

450468
LogPrintf("llmq", "CSigningManager::%s -- verified recovered sig(s). count=%d, vt=%d, nodes=%d\n", __func__, verifyCount, verifyTimer.count(), recSigsByNode.size());
451469

452-
std::unordered_set<uint256> processed;
470+
std::unordered_set<uint256, StaticSaltedHasher> processed;
453471
for (auto& p : recSigsByNode) {
454472
NodeId nodeId = p.first;
455473
auto& v = p.second;

src/llmq/quorums_signing.h

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,11 @@
1010

1111
#include "chainparams.h"
1212
#include "net.h"
13+
#include "saltedhasher.h"
1314
#include "sync.h"
1415

1516
#include <unordered_map>
1617

17-
namespace std
18-
{
19-
template <>
20-
struct hash<std::pair<Consensus::LLMQType, uint256>> {
21-
std::size_t operator()(const std::pair<Consensus::LLMQType, uint256>& k) const
22-
{
23-
return (std::size_t)((k.first + 1) * k.second.GetCheapHash());
24-
}
25-
};
26-
} // namespace std
27-
2818
namespace llmq
2919
{
3020

@@ -77,7 +67,6 @@ class CRecoveredSig
7767
}
7868
};
7969

80-
// TODO implement caching to speed things up
8170
class CRecoveredSigsDb
8271
{
8372
static const size_t MAX_CACHE_SIZE = 30000;
@@ -87,8 +76,9 @@ class CRecoveredSigsDb
8776
CDBWrapper db;
8877

8978
RecursiveMutex cs;
90-
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, std::pair<bool, int64_t>> hasSigForIdCache;
91-
std::unordered_map<uint256, std::pair<bool, int64_t>> hasSigForSessionCache;
79+
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, std::pair<bool, int64_t>, StaticSaltedHasher> hasSigForIdCache;
80+
std::unordered_map<uint256, std::pair<bool, int64_t>, StaticSaltedHasher> hasSigForSessionCache;
81+
std::unordered_map<uint256, std::pair<bool, int64_t>, StaticSaltedHasher> hasSigForHashCache;
9282

9383
public:
9484
CRecoveredSigsDb(bool fMemory);
@@ -157,7 +147,9 @@ class CSigningManager
157147
void ProcessMessageRecoveredSig(CNode* pfrom, const CRecoveredSig& recoveredSig, CConnman& connman);
158148
bool PreVerifyRecoveredSig(NodeId nodeId, const CRecoveredSig& recoveredSig, bool& retBan);
159149

160-
void CollectPendingRecoveredSigsToVerify(size_t maxUniqueSessions, std::unordered_map<NodeId, std::list<CRecoveredSig>>& retSigShares, std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr>& retQuorums);
150+
void CollectPendingRecoveredSigsToVerify(size_t maxUniqueSessions,
151+
std::unordered_map<NodeId, std::list<CRecoveredSig>>& retSigShares,
152+
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& retQuorums);
161153
bool ProcessPendingRecoveredSigs(CConnman& connman); // called from the worker thread of CSigSharesManager
162154
void ProcessRecoveredSig(NodeId nodeId, const CRecoveredSig& recoveredSig, const CQuorumCPtr& quorum, CConnman& connman);
163155
void Cleanup(); // called from the worker thread of CSigSharesManager

src/llmq/quorums_signing_shares.cpp

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ bool CSigSharesManager::PreVerifyBatchedSigShares(NodeId nodeId, const CBatchedS
380380
void CSigSharesManager::CollectPendingSigSharesToVerify(
381381
size_t maxUniqueSessions,
382382
std::unordered_map<NodeId, std::vector<CSigShare>>& retSigShares,
383-
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr>& retQuorums)
383+
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& retQuorums)
384384
{
385385
{
386386
LOCK(cs);
@@ -394,7 +394,7 @@ void CSigSharesManager::CollectPendingSigSharesToVerify(
394394
// invalid, making batch verification fail and revert to per-share verification, which in turn would slow down
395395
// the whole verification process
396396

397-
std::unordered_set<std::pair<NodeId, uint256>> uniqueSignHashes;
397+
std::unordered_set<std::pair<NodeId, uint256>, StaticSaltedHasher> uniqueSignHashes;
398398
llmq::utils::IterateNodesRandom(nodeStates, [&]() { return uniqueSignHashes.size() < maxUniqueSessions; }, [&](NodeId nodeId, CSigSharesNodeState& ns) {
399399
if (ns.pendingIncomingSigShares.Empty()) {
400400
return false;
@@ -439,7 +439,7 @@ void CSigSharesManager::CollectPendingSigSharesToVerify(
439439
bool CSigSharesManager::ProcessPendingSigShares(CConnman& connman)
440440
{
441441
std::unordered_map<NodeId, std::vector<CSigShare>> sigSharesByNodes;
442-
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr> quorums;
442+
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher> quorums;
443443

444444
CollectPendingSigSharesToVerify(32, sigSharesByNodes, quorums);
445445
if (sigSharesByNodes.empty()) {
@@ -508,7 +508,10 @@ bool CSigSharesManager::ProcessPendingSigShares(CConnman& connman)
508508
}
509509

510510
// It's ensured that no duplicates are passed to this method
511-
void CSigSharesManager::ProcessPendingSigSharesFromNode(NodeId nodeId, const std::vector<CSigShare>& sigShares, const std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr>& quorums, CConnman& connman)
511+
void CSigSharesManager::ProcessPendingSigSharesFromNode(NodeId nodeId,
512+
const std::vector<CSigShare>& sigShares,
513+
const std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& quorums,
514+
CConnman& connman)
512515
{
513516
LOCK(cs);
514517
auto& nodeState = nodeStates[nodeId];
@@ -660,11 +663,9 @@ void CSigSharesManager::TryRecoverSig(const CQuorumCPtr& quorum, const uint256&
660663
}
661664

662665
// cs must be held
663-
void CSigSharesManager::CollectSigSharesToRequest(std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv>>& sigSharesToRequest)
666+
void CSigSharesManager::CollectSigSharesToRequest(std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv, StaticSaltedHasher>>& sigSharesToRequest)
664667
{
665668
int64_t now = GetTimeMillis();
666-
std::unordered_map<SigShareKey, std::vector<NodeId>> nodesBySigShares;
667-
668669
const size_t maxRequestsForNode = 32;
669670

670671
// avoid requesting from same nodes all the time
@@ -695,7 +696,7 @@ void CSigSharesManager::CollectSigSharesToRequest(std::unordered_map<NodeId, std
695696
return false;
696697
});
697698

698-
std::unordered_map<uint256, CSigSharesInv>* invMap = nullptr;
699+
decltype(sigSharesToRequest.begin()->second)* invMap = nullptr;
699700

700701
for (auto& p2 : nodeState.sessions) {
701702
auto& signHash = p2.first;
@@ -756,7 +757,7 @@ void CSigSharesManager::CollectSigSharesToRequest(std::unordered_map<NodeId, std
756757
}
757758

758759
// cs must be held
759-
void CSigSharesManager::CollectSigSharesToSend(std::unordered_map<NodeId, std::unordered_map<uint256, CBatchedSigShares>>& sigSharesToSend)
760+
void CSigSharesManager::CollectSigSharesToSend(std::unordered_map<NodeId, std::unordered_map<uint256, CBatchedSigShares, StaticSaltedHasher>>& sigSharesToSend)
760761
{
761762
for (auto& p : nodeStates) {
762763
auto nodeId = p.first;
@@ -766,7 +767,7 @@ void CSigSharesManager::CollectSigSharesToSend(std::unordered_map<NodeId, std::u
766767
continue;
767768
}
768769

769-
std::unordered_map<uint256, CBatchedSigShares>* sigSharesToSend2 = nullptr;
770+
decltype(sigSharesToSend.begin()->second)* sigSharesToSend2 = nullptr;
770771

771772
for (auto& p2 : nodeState.sessions) {
772773
auto& signHash = p2.first;
@@ -813,9 +814,9 @@ void CSigSharesManager::CollectSigSharesToSend(std::unordered_map<NodeId, std::u
813814
}
814815

815816
// cs must be held
816-
void CSigSharesManager::CollectSigSharesToAnnounce(std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv>>& sigSharesToAnnounce)
817+
void CSigSharesManager::CollectSigSharesToAnnounce(std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv, StaticSaltedHasher>>& sigSharesToAnnounce)
817818
{
818-
std::unordered_set<std::pair<Consensus::LLMQType, uint256>> quorumNodesPrepared;
819+
std::unordered_set<std::pair<Consensus::LLMQType, uint256>, StaticSaltedHasher> quorumNodesPrepared;
819820

820821
this->sigSharesToAnnounce.ForEach([&](const SigShareKey& sigShareKey, bool) {
821822
auto& signHash = sigShareKey.first;
@@ -883,9 +884,9 @@ bool CSigSharesManager::SendMessages()
883884
nodesByAddress.emplace(pnode->addr, pnode->GetId());
884885
});
885886

886-
std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv>> sigSharesToRequest;
887-
std::unordered_map<NodeId, std::unordered_map<uint256, CBatchedSigShares>> sigSharesToSend;
888-
std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv>> sigSharesToAnnounce;
887+
std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv, StaticSaltedHasher>> sigSharesToRequest;
888+
std::unordered_map<NodeId, std::unordered_map<uint256, CBatchedSigShares, StaticSaltedHasher>> sigSharesToSend;
889+
std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv, StaticSaltedHasher>> sigSharesToAnnounce;
889890

890891
{
891892
LOCK(cs);
@@ -945,13 +946,13 @@ void CSigSharesManager::Cleanup()
945946
return;
946947
}
947948

948-
std::unordered_set<std::pair<Consensus::LLMQType, uint256>> quorumsToCheck;
949+
std::unordered_set<std::pair<Consensus::LLMQType, uint256>, StaticSaltedHasher> quorumsToCheck;
949950

950951
{
951952
LOCK(cs);
952953

953954
// Remove sessions which were successfully recovered
954-
std::unordered_set<uint256> doneSessions;
955+
std::unordered_set<uint256, StaticSaltedHasher> doneSessions;
955956
sigShares.ForEach([&](const SigShareKey& k, const CSigShare& sigShare) {
956957
if (doneSessions.count(sigShare.GetSignHash())) {
957958
return;
@@ -965,7 +966,7 @@ void CSigSharesManager::Cleanup()
965966
}
966967

967968
// Remove sessions which timed out
968-
std::unordered_set<uint256> timeoutSessions;
969+
std::unordered_set<uint256, StaticSaltedHasher> timeoutSessions;
969970
for (auto& p : timeSeenForSessions) {
970971
auto& signHash = p.first;
971972
int64_t firstSeenTime = p.second.first;
@@ -1009,7 +1010,7 @@ void CSigSharesManager::Cleanup()
10091010
{
10101011
// Now delete sessions which are for inactive quorums
10111012
LOCK(cs);
1012-
std::unordered_set<uint256> inactiveQuorumSessions;
1013+
std::unordered_set<uint256, StaticSaltedHasher> inactiveQuorumSessions;
10131014
sigShares.ForEach([&](const SigShareKey& k, const CSigShare& sigShare) {
10141015
if (quorumsToCheck.count(std::make_pair((Consensus::LLMQType)sigShare.llmqType, sigShare.quorumHash))) {
10151016
inactiveQuorumSessions.emplace(sigShare.GetSignHash());

src/llmq/quorums_signing_shares.h

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "consensus/params.h"
1111
#include "net.h"
1212
#include "random.h"
13+
#include "saltedhasher.h"
1314
#include "serialize.h"
1415
#include "sync.h"
1516
#include "tinyformat.h"
@@ -29,28 +30,6 @@ namespace llmq
2930
{
3031
// <signHash, quorumMember>
3132
typedef std::pair<uint256, uint16_t> SigShareKey;
32-
} // namespace llmq
33-
34-
namespace std
35-
{
36-
template <>
37-
struct hash<llmq::SigShareKey> {
38-
std::size_t operator()(const llmq::SigShareKey& k) const
39-
{
40-
return (std::size_t)((k.second + 1) * k.first.GetCheapHash());
41-
}
42-
};
43-
template <>
44-
struct hash<std::pair<NodeId, uint256>> {
45-
std::size_t operator()(const std::pair<NodeId, uint256>& k) const
46-
{
47-
return (std::size_t)((k.first + 1) * k.second.GetCheapHash());
48-
}
49-
};
50-
} // namespace std
51-
52-
namespace llmq
53-
{
5433

5534
// this one does not get transmitted over the wire as it is batched inside CBatchedSigShares
5635
class CSigShare
@@ -151,7 +130,7 @@ template <typename T>
151130
class SigShareMap
152131
{
153132
private:
154-
std::unordered_map<uint256, std::unordered_map<uint16_t, T>> internalMap;
133+
std::unordered_map<uint256, std::unordered_map<uint16_t, T>, StaticSaltedHasher> internalMap;
155134

156135
public:
157136
bool Add(const SigShareKey& k, const T& v)
@@ -340,7 +319,7 @@ class CSigSharesManager : public CRecoveredSigsListener
340319
SigShareMap<CSigShare> sigShares;
341320

342321
// stores time of first and last receivedSigShare. Used to detect timeouts
343-
std::unordered_map<uint256, std::pair<int64_t, int64_t>> timeSeenForSessions;
322+
std::unordered_map<uint256, std::pair<int64_t, int64_t>, StaticSaltedHasher> timeSeenForSessions;
344323

345324
std::unordered_map<NodeId, CSigSharesNodeState> nodeStates;
346325
SigShareMap<std::pair<NodeId, int64_t>> sigSharesRequested;
@@ -379,10 +358,15 @@ class CSigSharesManager : public CRecoveredSigsListener
379358
bool VerifySigSharesInv(NodeId from, const CSigSharesInv& inv);
380359
bool PreVerifyBatchedSigShares(NodeId nodeId, const CBatchedSigShares& batchedSigShares, bool& retBan);
381360

382-
void CollectPendingSigSharesToVerify(size_t maxUniqueSessions, std::unordered_map<NodeId, std::vector<CSigShare>>& retSigShares, std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr>& retQuorums);
361+
void CollectPendingSigSharesToVerify(size_t maxUniqueSessions,
362+
std::unordered_map<NodeId, std::vector<CSigShare>>& retSigShares,
363+
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& retQuorums);
383364
bool ProcessPendingSigShares(CConnman& connman);
384365

385-
void ProcessPendingSigSharesFromNode(NodeId nodeId, const std::vector<CSigShare>& sigShares, const std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr>& quorums, CConnman& connman);
366+
void ProcessPendingSigSharesFromNode(NodeId nodeId,
367+
const std::vector<CSigShare>& sigShares,
368+
const std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& quorums,
369+
CConnman& connman);
386370

387371
void ProcessSigShare(NodeId nodeId, const CSigShare& sigShare, CConnman& connman, const CQuorumCPtr& quorum);
388372
void TryRecoverSig(const CQuorumCPtr& quorum, const uint256& id, const uint256& msgHash, CConnman& connman);
@@ -395,9 +379,9 @@ class CSigSharesManager : public CRecoveredSigsListener
395379
void BanNode(NodeId nodeId);
396380

397381
bool SendMessages();
398-
void CollectSigSharesToRequest(std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv>>& sigSharesToRequest);
399-
void CollectSigSharesToSend(std::unordered_map<NodeId, std::unordered_map<uint256, CBatchedSigShares>>& sigSharesToSend);
400-
void CollectSigSharesToAnnounce(std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv>>& sigSharesToAnnounce);
382+
void CollectSigSharesToRequest(std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv, StaticSaltedHasher>>& sigSharesToRequest);
383+
void CollectSigSharesToSend(std::unordered_map<NodeId, std::unordered_map<uint256, CBatchedSigShares, StaticSaltedHasher>>& sigSharesToSend);
384+
void CollectSigSharesToAnnounce(std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv, StaticSaltedHasher>>& sigSharesToAnnounce);
401385
bool SignPendingSigShares();
402386
void WorkThreadMain();
403387
};

0 commit comments

Comments
 (0)