Merge pull request #2725 from codablock/pr_llmq_hashmaps
Add more caching to CRecoveredSigsDb and use salted hashing for externally provided keys
This commit is contained in:
commit
2249413a7c
@ -201,6 +201,7 @@ BITCOIN_CORE_H = \
|
|||||||
rpc/protocol.h \
|
rpc/protocol.h \
|
||||||
rpc/server.h \
|
rpc/server.h \
|
||||||
rpc/register.h \
|
rpc/register.h \
|
||||||
|
saltedhasher.h \
|
||||||
scheduler.h \
|
scheduler.h \
|
||||||
script/sigcache.h \
|
script/sigcache.h \
|
||||||
script/sign.h \
|
script/sign.h \
|
||||||
@ -463,6 +464,7 @@ libdash_common_a_SOURCES = \
|
|||||||
netaddress.cpp \
|
netaddress.cpp \
|
||||||
netbase.cpp \
|
netbase.cpp \
|
||||||
protocol.cpp \
|
protocol.cpp \
|
||||||
|
saltedhasher.cpp \
|
||||||
scheduler.cpp \
|
scheduler.cpp \
|
||||||
script/sign.cpp \
|
script/sign.cpp \
|
||||||
script/standard.cpp \
|
script/standard.cpp \
|
||||||
|
@ -199,6 +199,11 @@ bool CQuorumBlockProcessor::ProcessCommitment(const CBlockIndex* pindex, const C
|
|||||||
evoDb.Write(std::make_pair(DB_FIRST_MINED_COMMITMENT, (uint8_t)params.type), quorumHash);
|
evoDb.Write(std::make_pair(DB_FIRST_MINED_COMMITMENT, (uint8_t)params.type), quorumHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
LOCK(minableCommitmentsCs);
|
||||||
|
hasMinedCommitmentCache.erase(std::make_pair(params.type, quorumHash));
|
||||||
|
}
|
||||||
|
|
||||||
LogPrintf("CQuorumBlockProcessor::%s -- processed commitment from block. type=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s\n", __func__,
|
LogPrintf("CQuorumBlockProcessor::%s -- processed commitment from block. type=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s\n", __func__,
|
||||||
qc.llmqType, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
|
qc.llmqType, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
|
||||||
|
|
||||||
@ -222,6 +227,10 @@ bool CQuorumBlockProcessor::UndoBlock(const CBlock& block, const CBlockIndex* pi
|
|||||||
}
|
}
|
||||||
|
|
||||||
evoDb.Erase(std::make_pair(DB_MINED_COMMITMENT, std::make_pair(qc.llmqType, qc.quorumHash)));
|
evoDb.Erase(std::make_pair(DB_MINED_COMMITMENT, std::make_pair(qc.llmqType, qc.quorumHash)));
|
||||||
|
{
|
||||||
|
LOCK(minableCommitmentsCs);
|
||||||
|
hasMinedCommitmentCache.erase(std::make_pair((Consensus::LLMQType)qc.llmqType, qc.quorumHash));
|
||||||
|
}
|
||||||
|
|
||||||
// if a reorg happened, we should allow to mine this commitment later
|
// if a reorg happened, we should allow to mine this commitment later
|
||||||
AddMinableCommitment(qc);
|
AddMinableCommitment(qc);
|
||||||
@ -309,8 +318,21 @@ uint256 CQuorumBlockProcessor::GetQuorumBlockHash(Consensus::LLMQType llmqType,
|
|||||||
|
|
||||||
bool CQuorumBlockProcessor::HasMinedCommitment(Consensus::LLMQType llmqType, const uint256& quorumHash)
|
bool CQuorumBlockProcessor::HasMinedCommitment(Consensus::LLMQType llmqType, const uint256& quorumHash)
|
||||||
{
|
{
|
||||||
|
auto cacheKey = std::make_pair(llmqType, quorumHash);
|
||||||
|
{
|
||||||
|
LOCK(minableCommitmentsCs);
|
||||||
|
auto cacheIt = hasMinedCommitmentCache.find(cacheKey);
|
||||||
|
if (cacheIt != hasMinedCommitmentCache.end()) {
|
||||||
|
return cacheIt->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto key = std::make_pair(DB_MINED_COMMITMENT, std::make_pair((uint8_t)llmqType, quorumHash));
|
auto key = std::make_pair(DB_MINED_COMMITMENT, std::make_pair((uint8_t)llmqType, quorumHash));
|
||||||
return evoDb.Exists(key);
|
bool ret = evoDb.Exists(key);
|
||||||
|
|
||||||
|
LOCK(minableCommitmentsCs);
|
||||||
|
hasMinedCommitmentCache.emplace(cacheKey, ret);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CQuorumBlockProcessor::GetMinedCommitment(Consensus::LLMQType llmqType, const uint256& quorumHash, CFinalCommitment& ret)
|
bool CQuorumBlockProcessor::GetMinedCommitment(Consensus::LLMQType llmqType, const uint256& quorumHash, CFinalCommitment& ret)
|
||||||
|
@ -6,12 +6,15 @@
|
|||||||
#define DASH_QUORUMS_BLOCKPROCESSOR_H
|
#define DASH_QUORUMS_BLOCKPROCESSOR_H
|
||||||
|
|
||||||
#include "llmq/quorums_commitment.h"
|
#include "llmq/quorums_commitment.h"
|
||||||
|
#include "llmq/quorums_utils.h"
|
||||||
|
|
||||||
#include "consensus/params.h"
|
#include "consensus/params.h"
|
||||||
#include "primitives/transaction.h"
|
#include "primitives/transaction.h"
|
||||||
|
#include "saltedhasher.h"
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
class CNode;
|
class CNode;
|
||||||
class CConnman;
|
class CConnman;
|
||||||
@ -29,6 +32,8 @@ private:
|
|||||||
std::map<std::pair<Consensus::LLMQType, uint256>, uint256> minableCommitmentsByQuorum;
|
std::map<std::pair<Consensus::LLMQType, uint256>, uint256> minableCommitmentsByQuorum;
|
||||||
std::map<uint256, CFinalCommitment> minableCommitments;
|
std::map<uint256, CFinalCommitment> minableCommitments;
|
||||||
|
|
||||||
|
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, bool, StaticSaltedHasher> hasMinedCommitmentCache;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CQuorumBlockProcessor(CEvoDB& _evoDb) : evoDb(_evoDb) {}
|
CQuorumBlockProcessor(CEvoDB& _evoDb) : evoDb(_evoDb) {}
|
||||||
|
|
||||||
|
@ -81,8 +81,23 @@ bool CRecoveredSigsDb::HasRecoveredSigForSession(const uint256& signHash)
|
|||||||
|
|
||||||
bool CRecoveredSigsDb::HasRecoveredSigForHash(const uint256& hash)
|
bool CRecoveredSigsDb::HasRecoveredSigForHash(const uint256& hash)
|
||||||
{
|
{
|
||||||
|
int64_t t = GetTimeMillis();
|
||||||
|
|
||||||
|
{
|
||||||
|
LOCK(cs);
|
||||||
|
auto it = hasSigForHashCache.find(hash);
|
||||||
|
if (it != hasSigForHashCache.end()) {
|
||||||
|
it->second.second = t;
|
||||||
|
return it->second.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto k = std::make_tuple('h', hash);
|
auto k = std::make_tuple('h', hash);
|
||||||
return db.Exists(k);
|
bool ret = db.Exists(k);
|
||||||
|
|
||||||
|
LOCK(cs);
|
||||||
|
hasSigForHashCache.emplace(hash, std::make_pair(ret, t));
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CRecoveredSigsDb::ReadRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, CRecoveredSig& ret)
|
bool CRecoveredSigsDb::ReadRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, CRecoveredSig& ret)
|
||||||
@ -154,13 +169,14 @@ void CRecoveredSigsDb::WriteRecoveredSig(const llmq::CRecoveredSig& recSig)
|
|||||||
LOCK(cs);
|
LOCK(cs);
|
||||||
hasSigForIdCache[std::make_pair((Consensus::LLMQType)recSig.llmqType, recSig.id)] = std::make_pair(true, t);
|
hasSigForIdCache[std::make_pair((Consensus::LLMQType)recSig.llmqType, recSig.id)] = std::make_pair(true, t);
|
||||||
hasSigForSessionCache[signHash] = std::make_pair(true, t);
|
hasSigForSessionCache[signHash] = std::make_pair(true, t);
|
||||||
|
hasSigForHashCache[recSig.GetHash()] = std::make_pair(true, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename K>
|
template<typename K, typename H>
|
||||||
static void TruncateCacheMap(std::unordered_map<K, std::pair<bool, int64_t>>& m, size_t maxSize, size_t truncateThreshold)
|
static void TruncateCacheMap(std::unordered_map<K, std::pair<bool, int64_t>, H>& m, size_t maxSize, size_t truncateThreshold)
|
||||||
{
|
{
|
||||||
typedef typename std::unordered_map<K, std::pair<bool, int64_t>> Map;
|
typedef typename std::unordered_map<K, std::pair<bool, int64_t>, H> Map;
|
||||||
typedef typename Map::iterator Iterator;
|
typedef typename Map::iterator Iterator;
|
||||||
|
|
||||||
if (m.size() <= truncateThreshold) {
|
if (m.size() <= truncateThreshold) {
|
||||||
@ -239,10 +255,12 @@ void CRecoveredSigsDb::CleanupOldRecoveredSigs(int64_t maxAge)
|
|||||||
|
|
||||||
hasSigForIdCache.erase(std::make_pair((Consensus::LLMQType)recSig.llmqType, recSig.id));
|
hasSigForIdCache.erase(std::make_pair((Consensus::LLMQType)recSig.llmqType, recSig.id));
|
||||||
hasSigForSessionCache.erase(signHash);
|
hasSigForSessionCache.erase(signHash);
|
||||||
|
hasSigForHashCache.erase(recSig.GetHash());
|
||||||
}
|
}
|
||||||
|
|
||||||
TruncateCacheMap(hasSigForIdCache, MAX_CACHE_SIZE, MAX_CACHE_TRUNCATE_THRESHOLD);
|
TruncateCacheMap(hasSigForIdCache, MAX_CACHE_SIZE, MAX_CACHE_TRUNCATE_THRESHOLD);
|
||||||
TruncateCacheMap(hasSigForSessionCache, MAX_CACHE_SIZE, MAX_CACHE_TRUNCATE_THRESHOLD);
|
TruncateCacheMap(hasSigForSessionCache, MAX_CACHE_SIZE, MAX_CACHE_TRUNCATE_THRESHOLD);
|
||||||
|
TruncateCacheMap(hasSigForHashCache, MAX_CACHE_SIZE, MAX_CACHE_TRUNCATE_THRESHOLD);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& e : toDelete2) {
|
for (auto& e : toDelete2) {
|
||||||
@ -359,7 +377,7 @@ bool CSigningManager::PreVerifyRecoveredSig(NodeId nodeId, const CRecoveredSig&
|
|||||||
void CSigningManager::CollectPendingRecoveredSigsToVerify(
|
void CSigningManager::CollectPendingRecoveredSigsToVerify(
|
||||||
size_t maxUniqueSessions,
|
size_t maxUniqueSessions,
|
||||||
std::unordered_map<NodeId, std::list<CRecoveredSig>>& retSigShares,
|
std::unordered_map<NodeId, std::list<CRecoveredSig>>& retSigShares,
|
||||||
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr>& retQuorums)
|
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& retQuorums)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
LOCK(cs);
|
LOCK(cs);
|
||||||
@ -367,7 +385,7 @@ void CSigningManager::CollectPendingRecoveredSigsToVerify(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_set<std::pair<NodeId, uint256>> uniqueSignHashes;
|
std::unordered_set<std::pair<NodeId, uint256>, StaticSaltedHasher> uniqueSignHashes;
|
||||||
CLLMQUtils::IterateNodesRandom(pendingRecoveredSigs, [&]() {
|
CLLMQUtils::IterateNodesRandom(pendingRecoveredSigs, [&]() {
|
||||||
return uniqueSignHashes.size() < maxUniqueSessions;
|
return uniqueSignHashes.size() < maxUniqueSessions;
|
||||||
}, [&](NodeId nodeId, std::list<CRecoveredSig>& ns) {
|
}, [&](NodeId nodeId, std::list<CRecoveredSig>& ns) {
|
||||||
@ -425,7 +443,7 @@ void CSigningManager::CollectPendingRecoveredSigsToVerify(
|
|||||||
bool CSigningManager::ProcessPendingRecoveredSigs(CConnman& connman)
|
bool CSigningManager::ProcessPendingRecoveredSigs(CConnman& connman)
|
||||||
{
|
{
|
||||||
std::unordered_map<NodeId, std::list<CRecoveredSig>> recSigsByNode;
|
std::unordered_map<NodeId, std::list<CRecoveredSig>> recSigsByNode;
|
||||||
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr> quorums;
|
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher> quorums;
|
||||||
|
|
||||||
CollectPendingRecoveredSigsToVerify(32, recSigsByNode, quorums);
|
CollectPendingRecoveredSigsToVerify(32, recSigsByNode, quorums);
|
||||||
if (recSigsByNode.empty()) {
|
if (recSigsByNode.empty()) {
|
||||||
@ -454,7 +472,7 @@ bool CSigningManager::ProcessPendingRecoveredSigs(CConnman& connman)
|
|||||||
|
|
||||||
LogPrint("llmq", "CSigningManager::%s -- verified recovered sig(s). count=%d, vt=%d, nodes=%d\n", __func__, verifyCount, verifyTimer.count(), recSigsByNode.size());
|
LogPrint("llmq", "CSigningManager::%s -- verified recovered sig(s). count=%d, vt=%d, nodes=%d\n", __func__, verifyCount, verifyTimer.count(), recSigsByNode.size());
|
||||||
|
|
||||||
std::unordered_set<uint256> processed;
|
std::unordered_set<uint256, StaticSaltedHasher> processed;
|
||||||
for (auto& p : recSigsByNode) {
|
for (auto& p : recSigsByNode) {
|
||||||
NodeId nodeId = p.first;
|
NodeId nodeId = p.first;
|
||||||
auto& v = p.second;
|
auto& v = p.second;
|
||||||
|
@ -9,20 +9,10 @@
|
|||||||
|
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "chainparams.h"
|
#include "chainparams.h"
|
||||||
|
#include "saltedhasher.h"
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace std {
|
|
||||||
template <>
|
|
||||||
struct hash<std::pair<Consensus::LLMQType, uint256>>
|
|
||||||
{
|
|
||||||
std::size_t operator()(const std::pair<Consensus::LLMQType, uint256>& k) const
|
|
||||||
{
|
|
||||||
return (std::size_t)((k.first + 1) * k.second.GetCheapHash());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace llmq
|
namespace llmq
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -76,7 +66,6 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO implement caching to speed things up
|
|
||||||
class CRecoveredSigsDb
|
class CRecoveredSigsDb
|
||||||
{
|
{
|
||||||
static const size_t MAX_CACHE_SIZE = 30000;
|
static const size_t MAX_CACHE_SIZE = 30000;
|
||||||
@ -86,8 +75,9 @@ private:
|
|||||||
CDBWrapper db;
|
CDBWrapper db;
|
||||||
|
|
||||||
CCriticalSection cs;
|
CCriticalSection cs;
|
||||||
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, std::pair<bool, int64_t>> hasSigForIdCache;
|
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, std::pair<bool, int64_t>, StaticSaltedHasher> hasSigForIdCache;
|
||||||
std::unordered_map<uint256, std::pair<bool, int64_t>> hasSigForSessionCache;
|
std::unordered_map<uint256, std::pair<bool, int64_t>, StaticSaltedHasher> hasSigForSessionCache;
|
||||||
|
std::unordered_map<uint256, std::pair<bool, int64_t>, StaticSaltedHasher> hasSigForHashCache;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CRecoveredSigsDb(bool fMemory);
|
CRecoveredSigsDb(bool fMemory);
|
||||||
@ -156,7 +146,9 @@ private:
|
|||||||
void ProcessMessageRecoveredSig(CNode* pfrom, const CRecoveredSig& recoveredSig, CConnman& connman);
|
void ProcessMessageRecoveredSig(CNode* pfrom, const CRecoveredSig& recoveredSig, CConnman& connman);
|
||||||
bool PreVerifyRecoveredSig(NodeId nodeId, const CRecoveredSig& recoveredSig, bool& retBan);
|
bool PreVerifyRecoveredSig(NodeId nodeId, const CRecoveredSig& recoveredSig, bool& retBan);
|
||||||
|
|
||||||
void CollectPendingRecoveredSigsToVerify(size_t maxUniqueSessions, std::unordered_map<NodeId, std::list<CRecoveredSig>>& retSigShares, std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr>& retQuorums);
|
void CollectPendingRecoveredSigsToVerify(size_t maxUniqueSessions,
|
||||||
|
std::unordered_map<NodeId, std::list<CRecoveredSig>>& retSigShares,
|
||||||
|
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& retQuorums);
|
||||||
bool ProcessPendingRecoveredSigs(CConnman& connman); // called from the worker thread of CSigSharesManager
|
bool ProcessPendingRecoveredSigs(CConnman& connman); // called from the worker thread of CSigSharesManager
|
||||||
void ProcessRecoveredSig(NodeId nodeId, const CRecoveredSig& recoveredSig, const CQuorumCPtr& quorum, CConnman& connman);
|
void ProcessRecoveredSig(NodeId nodeId, const CRecoveredSig& recoveredSig, const CQuorumCPtr& quorum, CConnman& connman);
|
||||||
void Cleanup(); // called from the worker thread of CSigSharesManager
|
void Cleanup(); // called from the worker thread of CSigSharesManager
|
||||||
|
@ -386,7 +386,7 @@ bool CSigSharesManager::PreVerifyBatchedSigShares(NodeId nodeId, const CBatchedS
|
|||||||
void CSigSharesManager::CollectPendingSigSharesToVerify(
|
void CSigSharesManager::CollectPendingSigSharesToVerify(
|
||||||
size_t maxUniqueSessions,
|
size_t maxUniqueSessions,
|
||||||
std::unordered_map<NodeId, std::vector<CSigShare>>& retSigShares,
|
std::unordered_map<NodeId, std::vector<CSigShare>>& retSigShares,
|
||||||
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr>& retQuorums)
|
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& retQuorums)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
LOCK(cs);
|
LOCK(cs);
|
||||||
@ -400,7 +400,7 @@ void CSigSharesManager::CollectPendingSigSharesToVerify(
|
|||||||
// invalid, making batch verification fail and revert to per-share verification, which in turn would slow down
|
// invalid, making batch verification fail and revert to per-share verification, which in turn would slow down
|
||||||
// the whole verification process
|
// the whole verification process
|
||||||
|
|
||||||
std::unordered_set<std::pair<NodeId, uint256>> uniqueSignHashes;
|
std::unordered_set<std::pair<NodeId, uint256>, StaticSaltedHasher> uniqueSignHashes;
|
||||||
CLLMQUtils::IterateNodesRandom(nodeStates, [&]() {
|
CLLMQUtils::IterateNodesRandom(nodeStates, [&]() {
|
||||||
return uniqueSignHashes.size() < maxUniqueSessions;
|
return uniqueSignHashes.size() < maxUniqueSessions;
|
||||||
}, [&](NodeId nodeId, CSigSharesNodeState& ns) {
|
}, [&](NodeId nodeId, CSigSharesNodeState& ns) {
|
||||||
@ -448,7 +448,7 @@ void CSigSharesManager::CollectPendingSigSharesToVerify(
|
|||||||
bool CSigSharesManager::ProcessPendingSigShares(CConnman& connman)
|
bool CSigSharesManager::ProcessPendingSigShares(CConnman& connman)
|
||||||
{
|
{
|
||||||
std::unordered_map<NodeId, std::vector<CSigShare>> sigSharesByNodes;
|
std::unordered_map<NodeId, std::vector<CSigShare>> sigSharesByNodes;
|
||||||
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr> quorums;
|
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher> quorums;
|
||||||
|
|
||||||
CollectPendingSigSharesToVerify(32, sigSharesByNodes, quorums);
|
CollectPendingSigSharesToVerify(32, sigSharesByNodes, quorums);
|
||||||
if (sigSharesByNodes.empty()) {
|
if (sigSharesByNodes.empty()) {
|
||||||
@ -517,7 +517,10 @@ bool CSigSharesManager::ProcessPendingSigShares(CConnman& connman)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// It's ensured that no duplicates are passed to this method
|
// It's ensured that no duplicates are passed to this method
|
||||||
void CSigSharesManager::ProcessPendingSigSharesFromNode(NodeId nodeId, const std::vector<CSigShare>& sigShares, const std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr>& quorums, CConnman& connman)
|
void CSigSharesManager::ProcessPendingSigSharesFromNode(NodeId nodeId,
|
||||||
|
const std::vector<CSigShare>& sigShares,
|
||||||
|
const std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& quorums,
|
||||||
|
CConnman& connman)
|
||||||
{
|
{
|
||||||
auto& nodeState = nodeStates[nodeId];
|
auto& nodeState = nodeStates[nodeId];
|
||||||
|
|
||||||
@ -668,11 +671,9 @@ void CSigSharesManager::TryRecoverSig(const CQuorumCPtr& quorum, const uint256&
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cs must be held
|
// cs must be held
|
||||||
void CSigSharesManager::CollectSigSharesToRequest(std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv>>& sigSharesToRequest)
|
void CSigSharesManager::CollectSigSharesToRequest(std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv, StaticSaltedHasher>>& sigSharesToRequest)
|
||||||
{
|
{
|
||||||
int64_t now = GetTimeMillis();
|
int64_t now = GetTimeMillis();
|
||||||
std::unordered_map<SigShareKey, std::vector<NodeId>> nodesBySigShares;
|
|
||||||
|
|
||||||
const size_t maxRequestsForNode = 32;
|
const size_t maxRequestsForNode = 32;
|
||||||
|
|
||||||
// avoid requesting from same nodes all the time
|
// avoid requesting from same nodes all the time
|
||||||
@ -703,7 +704,7 @@ void CSigSharesManager::CollectSigSharesToRequest(std::unordered_map<NodeId, std
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
std::unordered_map<uint256, CSigSharesInv>* invMap = nullptr;
|
decltype(sigSharesToRequest.begin()->second)* invMap = nullptr;
|
||||||
|
|
||||||
for (auto& p2 : nodeState.sessions) {
|
for (auto& p2 : nodeState.sessions) {
|
||||||
auto& signHash = p2.first;
|
auto& signHash = p2.first;
|
||||||
@ -764,7 +765,7 @@ void CSigSharesManager::CollectSigSharesToRequest(std::unordered_map<NodeId, std
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cs must be held
|
// cs must be held
|
||||||
void CSigSharesManager::CollectSigSharesToSend(std::unordered_map<NodeId, std::unordered_map<uint256, CBatchedSigShares>>& sigSharesToSend)
|
void CSigSharesManager::CollectSigSharesToSend(std::unordered_map<NodeId, std::unordered_map<uint256, CBatchedSigShares, StaticSaltedHasher>>& sigSharesToSend)
|
||||||
{
|
{
|
||||||
for (auto& p : nodeStates) {
|
for (auto& p : nodeStates) {
|
||||||
auto nodeId = p.first;
|
auto nodeId = p.first;
|
||||||
@ -774,7 +775,7 @@ void CSigSharesManager::CollectSigSharesToSend(std::unordered_map<NodeId, std::u
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<uint256, CBatchedSigShares>* sigSharesToSend2 = nullptr;
|
decltype(sigSharesToSend.begin()->second)* sigSharesToSend2 = nullptr;
|
||||||
|
|
||||||
for (auto& p2 : nodeState.sessions) {
|
for (auto& p2 : nodeState.sessions) {
|
||||||
auto& signHash = p2.first;
|
auto& signHash = p2.first;
|
||||||
@ -821,9 +822,9 @@ void CSigSharesManager::CollectSigSharesToSend(std::unordered_map<NodeId, std::u
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cs must be held
|
// cs must be held
|
||||||
void CSigSharesManager::CollectSigSharesToAnnounce(std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv>>& sigSharesToAnnounce)
|
void CSigSharesManager::CollectSigSharesToAnnounce(std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv, StaticSaltedHasher>>& sigSharesToAnnounce)
|
||||||
{
|
{
|
||||||
std::unordered_set<std::pair<Consensus::LLMQType, uint256>> quorumNodesPrepared;
|
std::unordered_set<std::pair<Consensus::LLMQType, uint256>, StaticSaltedHasher> quorumNodesPrepared;
|
||||||
|
|
||||||
this->sigSharesToAnnounce.ForEach([&](const SigShareKey& sigShareKey, bool) {
|
this->sigSharesToAnnounce.ForEach([&](const SigShareKey& sigShareKey, bool) {
|
||||||
auto& signHash = sigShareKey.first;
|
auto& signHash = sigShareKey.first;
|
||||||
@ -890,9 +891,9 @@ bool CSigSharesManager::SendMessages()
|
|||||||
nodesByAddress.emplace(pnode->addr, pnode->id);
|
nodesByAddress.emplace(pnode->addr, pnode->id);
|
||||||
});
|
});
|
||||||
|
|
||||||
std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv>> sigSharesToRequest;
|
std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv, StaticSaltedHasher>> sigSharesToRequest;
|
||||||
std::unordered_map<NodeId, std::unordered_map<uint256, CBatchedSigShares>> sigSharesToSend;
|
std::unordered_map<NodeId, std::unordered_map<uint256, CBatchedSigShares, StaticSaltedHasher>> sigSharesToSend;
|
||||||
std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv>> sigSharesToAnnounce;
|
std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv, StaticSaltedHasher>> sigSharesToAnnounce;
|
||||||
|
|
||||||
{
|
{
|
||||||
LOCK(cs);
|
LOCK(cs);
|
||||||
@ -956,13 +957,13 @@ void CSigSharesManager::Cleanup()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_set<std::pair<Consensus::LLMQType, uint256>> quorumsToCheck;
|
std::unordered_set<std::pair<Consensus::LLMQType, uint256>, StaticSaltedHasher> quorumsToCheck;
|
||||||
|
|
||||||
{
|
{
|
||||||
LOCK(cs);
|
LOCK(cs);
|
||||||
|
|
||||||
// Remove sessions which were succesfully recovered
|
// Remove sessions which were succesfully recovered
|
||||||
std::unordered_set<uint256> doneSessions;
|
std::unordered_set<uint256, StaticSaltedHasher> doneSessions;
|
||||||
sigShares.ForEach([&](const SigShareKey& k, const CSigShare& sigShare) {
|
sigShares.ForEach([&](const SigShareKey& k, const CSigShare& sigShare) {
|
||||||
if (doneSessions.count(sigShare.GetSignHash())) {
|
if (doneSessions.count(sigShare.GetSignHash())) {
|
||||||
return;
|
return;
|
||||||
@ -976,7 +977,7 @@ void CSigSharesManager::Cleanup()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove sessions which timed out
|
// Remove sessions which timed out
|
||||||
std::unordered_set<uint256> timeoutSessions;
|
std::unordered_set<uint256, StaticSaltedHasher> timeoutSessions;
|
||||||
for (auto& p : timeSeenForSessions) {
|
for (auto& p : timeSeenForSessions) {
|
||||||
auto& signHash = p.first;
|
auto& signHash = p.first;
|
||||||
int64_t firstSeenTime = p.second.first;
|
int64_t firstSeenTime = p.second.first;
|
||||||
@ -1020,7 +1021,7 @@ void CSigSharesManager::Cleanup()
|
|||||||
{
|
{
|
||||||
// Now delete sessions which are for inactive quorums
|
// Now delete sessions which are for inactive quorums
|
||||||
LOCK(cs);
|
LOCK(cs);
|
||||||
std::unordered_set<uint256> inactiveQuorumSessions;
|
std::unordered_set<uint256, StaticSaltedHasher> inactiveQuorumSessions;
|
||||||
sigShares.ForEach([&](const SigShareKey& k, const CSigShare& sigShare) {
|
sigShares.ForEach([&](const SigShareKey& k, const CSigShare& sigShare) {
|
||||||
if (quorumsToCheck.count(std::make_pair((Consensus::LLMQType)sigShare.llmqType, sigShare.quorumHash))) {
|
if (quorumsToCheck.count(std::make_pair((Consensus::LLMQType)sigShare.llmqType, sigShare.quorumHash))) {
|
||||||
inactiveQuorumSessions.emplace(sigShare.GetSignHash());
|
inactiveQuorumSessions.emplace(sigShare.GetSignHash());
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "chainparams.h"
|
#include "chainparams.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
|
#include "saltedhasher.h"
|
||||||
#include "serialize.h"
|
#include "serialize.h"
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
#include "tinyformat.h"
|
#include "tinyformat.h"
|
||||||
@ -28,29 +29,6 @@ namespace llmq
|
|||||||
{
|
{
|
||||||
// <signHash, quorumMember>
|
// <signHash, quorumMember>
|
||||||
typedef std::pair<uint256, uint16_t> SigShareKey;
|
typedef std::pair<uint256, uint16_t> SigShareKey;
|
||||||
}
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
template <>
|
|
||||||
struct hash<llmq::SigShareKey>
|
|
||||||
{
|
|
||||||
std::size_t operator()(const llmq::SigShareKey& k) const
|
|
||||||
{
|
|
||||||
return (std::size_t)((k.second + 1) * k.first.GetCheapHash());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template <>
|
|
||||||
struct hash<std::pair<NodeId, uint256>>
|
|
||||||
{
|
|
||||||
std::size_t operator()(const std::pair<NodeId, uint256>& k) const
|
|
||||||
{
|
|
||||||
return (std::size_t)((k.first + 1) * k.second.GetCheapHash());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace llmq
|
|
||||||
{
|
|
||||||
|
|
||||||
// this one does not get transmitted over the wire as it is batched inside CBatchedSigShares
|
// this one does not get transmitted over the wire as it is batched inside CBatchedSigShares
|
||||||
class CSigShare
|
class CSigShare
|
||||||
@ -158,7 +136,7 @@ template<typename T>
|
|||||||
class SigShareMap
|
class SigShareMap
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::unordered_map<uint256, std::unordered_map<uint16_t, T>> internalMap;
|
std::unordered_map<uint256, std::unordered_map<uint16_t, T>, StaticSaltedHasher> internalMap;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool Add(const SigShareKey& k, const T& v)
|
bool Add(const SigShareKey& k, const T& v)
|
||||||
@ -308,14 +286,14 @@ public:
|
|||||||
CSigSharesInv knows;
|
CSigSharesInv knows;
|
||||||
};
|
};
|
||||||
// TODO limit number of sessions per node
|
// TODO limit number of sessions per node
|
||||||
std::unordered_map<uint256, Session> sessions;
|
std::unordered_map<uint256, Session, StaticSaltedHasher> sessions;
|
||||||
|
|
||||||
SigShareMap<CSigShare> pendingIncomingSigShares;
|
SigShareMap<CSigShare> pendingIncomingSigShares;
|
||||||
SigShareMap<int64_t> requestedSigShares;
|
SigShareMap<int64_t> requestedSigShares;
|
||||||
|
|
||||||
// elements are added whenever we receive a valid sig share from this node
|
// elements are added whenever we receive a valid sig share from this node
|
||||||
// this triggers us to send inventory items to him as he seems to be interested in these
|
// this triggers us to send inventory items to him as he seems to be interested in these
|
||||||
std::unordered_set<std::pair<Consensus::LLMQType, uint256>> interestedIn;
|
std::unordered_set<std::pair<Consensus::LLMQType, uint256>, StaticSaltedHasher> interestedIn;
|
||||||
|
|
||||||
bool banned{false};
|
bool banned{false};
|
||||||
|
|
||||||
@ -347,7 +325,7 @@ private:
|
|||||||
SigShareMap<CSigShare> sigShares;
|
SigShareMap<CSigShare> sigShares;
|
||||||
|
|
||||||
// stores time of first and last receivedSigShare. Used to detect timeouts
|
// stores time of first and last receivedSigShare. Used to detect timeouts
|
||||||
std::unordered_map<uint256, std::pair<int64_t, int64_t>> timeSeenForSessions;
|
std::unordered_map<uint256, std::pair<int64_t, int64_t>, StaticSaltedHasher> timeSeenForSessions;
|
||||||
|
|
||||||
std::unordered_map<NodeId, CSigSharesNodeState> nodeStates;
|
std::unordered_map<NodeId, CSigSharesNodeState> nodeStates;
|
||||||
SigShareMap<std::pair<NodeId, int64_t>> sigSharesRequested;
|
SigShareMap<std::pair<NodeId, int64_t>> sigSharesRequested;
|
||||||
@ -386,10 +364,15 @@ private:
|
|||||||
bool VerifySigSharesInv(NodeId from, const CSigSharesInv& inv);
|
bool VerifySigSharesInv(NodeId from, const CSigSharesInv& inv);
|
||||||
bool PreVerifyBatchedSigShares(NodeId nodeId, const CBatchedSigShares& batchedSigShares, bool& retBan);
|
bool PreVerifyBatchedSigShares(NodeId nodeId, const CBatchedSigShares& batchedSigShares, bool& retBan);
|
||||||
|
|
||||||
void CollectPendingSigSharesToVerify(size_t maxUniqueSessions, std::unordered_map<NodeId, std::vector<CSigShare>>& retSigShares, std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr>& retQuorums);
|
void CollectPendingSigSharesToVerify(size_t maxUniqueSessions,
|
||||||
|
std::unordered_map<NodeId, std::vector<CSigShare>>& retSigShares,
|
||||||
|
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& retQuorums);
|
||||||
bool ProcessPendingSigShares(CConnman& connman);
|
bool ProcessPendingSigShares(CConnman& connman);
|
||||||
|
|
||||||
void ProcessPendingSigSharesFromNode(NodeId nodeId, const std::vector<CSigShare>& sigShares, const std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr>& quorums, CConnman& connman);
|
void ProcessPendingSigSharesFromNode(NodeId nodeId,
|
||||||
|
const std::vector<CSigShare>& sigShares,
|
||||||
|
const std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& quorums,
|
||||||
|
CConnman& connman);
|
||||||
|
|
||||||
void ProcessSigShare(NodeId nodeId, const CSigShare& sigShare, CConnman& connman, const CQuorumCPtr& quorum);
|
void ProcessSigShare(NodeId nodeId, const CSigShare& sigShare, CConnman& connman, const CQuorumCPtr& quorum);
|
||||||
void TryRecoverSig(const CQuorumCPtr& quorum, const uint256& id, const uint256& msgHash, CConnman& connman);
|
void TryRecoverSig(const CQuorumCPtr& quorum, const uint256& id, const uint256& msgHash, CConnman& connman);
|
||||||
@ -402,9 +385,9 @@ private:
|
|||||||
void BanNode(NodeId nodeId);
|
void BanNode(NodeId nodeId);
|
||||||
|
|
||||||
bool SendMessages();
|
bool SendMessages();
|
||||||
void CollectSigSharesToRequest(std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv>>& sigSharesToRequest);
|
void CollectSigSharesToRequest(std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv, StaticSaltedHasher>>& sigSharesToRequest);
|
||||||
void CollectSigSharesToSend(std::unordered_map<NodeId, std::unordered_map<uint256, CBatchedSigShares>>& sigSharesToSend);
|
void CollectSigSharesToSend(std::unordered_map<NodeId, std::unordered_map<uint256, CBatchedSigShares, StaticSaltedHasher>>& sigSharesToSend);
|
||||||
void CollectSigSharesToAnnounce(std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv>>& sigSharesToAnnounce);
|
void CollectSigSharesToAnnounce(std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv, StaticSaltedHasher>>& sigSharesToAnnounce);
|
||||||
bool SignPendingSigShares();
|
bool SignPendingSigShares();
|
||||||
void WorkThreadMain();
|
void WorkThreadMain();
|
||||||
};
|
};
|
||||||
|
12
src/saltedhasher.cpp
Normal file
12
src/saltedhasher.cpp
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// Copyright (c) 2019 The Dash Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include "saltedhasher.h"
|
||||||
|
#include "random.h"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
SaltedHasherBase::SaltedHasherBase() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
|
||||||
|
|
||||||
|
SaltedHasherBase StaticSaltedHasher::s;
|
75
src/saltedhasher.h
Normal file
75
src/saltedhasher.h
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
// Copyright (c) 2019 The Dash Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#ifndef SALTEDHASHER_H
|
||||||
|
#define SALTEDHASHER_H
|
||||||
|
|
||||||
|
#include "hash.h"
|
||||||
|
#include "uint256.h"
|
||||||
|
|
||||||
|
/** Helper classes for std::unordered_map and std::unordered_set hashing */
|
||||||
|
|
||||||
|
template<typename T> struct SaltedHasherImpl;
|
||||||
|
|
||||||
|
template<typename N>
|
||||||
|
struct SaltedHasherImpl<std::pair<uint256, N>>
|
||||||
|
{
|
||||||
|
static std::size_t CalcHash(const std::pair<uint256, N>& v, uint64_t k0, uint64_t k1)
|
||||||
|
{
|
||||||
|
return SipHashUint256Extra(k0, k1, v.first, (uint32_t) v.second);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename N>
|
||||||
|
struct SaltedHasherImpl<std::pair<N, uint256>>
|
||||||
|
{
|
||||||
|
static std::size_t CalcHash(const std::pair<N, uint256>& v, uint64_t k0, uint64_t k1)
|
||||||
|
{
|
||||||
|
return SipHashUint256Extra(k0, k1, v.second, (uint32_t) v.first);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct SaltedHasherImpl<uint256>
|
||||||
|
{
|
||||||
|
static std::size_t CalcHash(const uint256& v, uint64_t k0, uint64_t k1)
|
||||||
|
{
|
||||||
|
return SipHashUint256(k0, k1, v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SaltedHasherBase
|
||||||
|
{
|
||||||
|
/** Salt */
|
||||||
|
const uint64_t k0, k1;
|
||||||
|
|
||||||
|
SaltedHasherBase();
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Allows each instance of unordered maps/sest to have their own salt */
|
||||||
|
template<typename T, typename S>
|
||||||
|
struct SaltedHasher
|
||||||
|
{
|
||||||
|
S s;
|
||||||
|
std::size_t operator()(const T& v) const
|
||||||
|
{
|
||||||
|
return SaltedHasherImpl<T>::CalcHash(v, s.k0, s.k1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Allows to use a static salt for all instances. The salt is a random value set at startup
|
||||||
|
* (through static initialization)
|
||||||
|
*/
|
||||||
|
struct StaticSaltedHasher
|
||||||
|
{
|
||||||
|
static SaltedHasherBase s;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::size_t operator()(const T& v) const
|
||||||
|
{
|
||||||
|
return SaltedHasherImpl<T>::CalcHash(v, s.k0, s.k1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif//SALTEDHASHER_H
|
Loading…
Reference in New Issue
Block a user