2019-01-29 15:53:14 +01:00
|
|
|
// Copyright (c) 2018-2019 The Dash Core developers
|
2018-11-23 15:42:09 +01:00
|
|
|
// Distributed under the MIT software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
2019-01-15 15:35:26 +01:00
|
|
|
#include "quorums.h"
|
2018-11-23 15:42:09 +01:00
|
|
|
#include "quorums_utils.h"
|
|
|
|
|
|
|
|
#include "chainparams.h"
|
|
|
|
#include "random.h"
|
2019-01-15 15:35:26 +01:00
|
|
|
#include "validation.h"
|
2018-11-23 15:42:09 +01:00
|
|
|
|
|
|
|
namespace llmq
|
|
|
|
{
|
|
|
|
|
2019-07-09 07:59:57 +02:00
|
|
|
std::vector<CDeterministicMNCPtr> CLLMQUtils::GetAllQuorumMembers(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum)
|
2018-11-23 15:42:09 +01:00
|
|
|
{
|
|
|
|
auto& params = Params().GetConsensus().llmqs.at(llmqType);
|
2019-07-09 07:59:57 +02:00
|
|
|
auto allMns = deterministicMNManager->GetListForBlock(pindexQuorum);
|
|
|
|
auto modifier = ::SerializeHash(std::make_pair(llmqType, pindexQuorum->GetBlockHash()));
|
2018-11-23 15:42:09 +01:00
|
|
|
return allMns.CalculateQuorum(params.size, modifier);
|
|
|
|
}
|
|
|
|
|
2019-05-28 15:34:41 +02:00
|
|
|
uint256 CLLMQUtils::BuildCommitmentHash(Consensus::LLMQType llmqType, const uint256& blockHash, const std::vector<bool>& validMembers, const CBLSPublicKey& pubKey, const uint256& vvecHash)
|
2018-11-23 15:42:09 +01:00
|
|
|
{
|
|
|
|
CHashWriter hw(SER_NETWORK, 0);
|
|
|
|
hw << llmqType;
|
|
|
|
hw << blockHash;
|
|
|
|
hw << DYNBITSET(validMembers);
|
|
|
|
hw << pubKey;
|
|
|
|
hw << vvecHash;
|
|
|
|
return hw.GetHash();
|
|
|
|
}
|
|
|
|
|
2019-01-15 15:35:26 +01:00
|
|
|
uint256 CLLMQUtils::BuildSignHash(Consensus::LLMQType llmqType, const uint256& quorumHash, const uint256& id, const uint256& msgHash)
|
|
|
|
{
|
|
|
|
CHashWriter h(SER_GETHASH, 0);
|
2019-05-28 15:34:41 +02:00
|
|
|
h << llmqType;
|
2019-01-15 15:35:26 +01:00
|
|
|
h << quorumHash;
|
|
|
|
h << id;
|
|
|
|
h << msgHash;
|
|
|
|
return h.GetHash();
|
|
|
|
}
|
|
|
|
|
2019-07-09 07:59:57 +02:00
|
|
|
std::set<uint256> CLLMQUtils::GetQuorumConnections(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum, const uint256& forMember)
|
2018-05-24 16:14:55 +02:00
|
|
|
{
|
|
|
|
auto& params = Params().GetConsensus().llmqs.at(llmqType);
|
|
|
|
|
2019-07-09 07:59:57 +02:00
|
|
|
auto mns = GetAllQuorumMembers(llmqType, pindexQuorum);
|
2019-04-09 12:22:46 +02:00
|
|
|
std::set<uint256> result;
|
2018-05-24 16:14:55 +02:00
|
|
|
for (size_t i = 0; i < mns.size(); i++) {
|
|
|
|
auto& dmn = mns[i];
|
|
|
|
if (dmn->proTxHash == forMember) {
|
2019-03-22 11:51:12 +01:00
|
|
|
// Connect to nodes at indexes (i+2^k)%n, where
|
|
|
|
// k: 0..max(1, floor(log2(n-1))-1)
|
|
|
|
// n: size of the quorum/ring
|
2019-02-19 11:05:39 +01:00
|
|
|
int gap = 1;
|
2019-03-22 11:51:12 +01:00
|
|
|
int gap_max = (int)mns.size() - 1;
|
|
|
|
int k = 0;
|
|
|
|
while ((gap_max >>= 1) || k <= 1) {
|
2019-02-19 11:05:39 +01:00
|
|
|
size_t idx = (i + gap) % mns.size();
|
2018-05-24 16:14:55 +02:00
|
|
|
auto& otherDmn = mns[idx];
|
|
|
|
if (otherDmn == dmn) {
|
|
|
|
continue;
|
|
|
|
}
|
2019-04-09 12:22:46 +02:00
|
|
|
result.emplace(otherDmn->proTxHash);
|
2019-02-19 11:05:39 +01:00
|
|
|
gap <<= 1;
|
2019-03-22 11:51:12 +01:00
|
|
|
k++;
|
2018-05-24 16:14:55 +02:00
|
|
|
}
|
2019-02-19 11:05:39 +01:00
|
|
|
// there can be no two members with the same proTxHash, so return early
|
|
|
|
break;
|
2018-05-24 16:14:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-07-09 07:59:57 +02:00
|
|
|
std::set<size_t> CLLMQUtils::CalcDeterministicWatchConnections(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum, size_t memberCount, size_t connectionCount)
|
2018-05-24 16:14:55 +02:00
|
|
|
{
|
|
|
|
static uint256 qwatchConnectionSeed;
|
|
|
|
static std::atomic<bool> qwatchConnectionSeedGenerated{false};
|
|
|
|
static CCriticalSection qwatchConnectionSeedCs;
|
|
|
|
if (!qwatchConnectionSeedGenerated) {
|
|
|
|
LOCK(qwatchConnectionSeedCs);
|
|
|
|
if (!qwatchConnectionSeedGenerated) {
|
|
|
|
qwatchConnectionSeed = GetRandHash();
|
|
|
|
qwatchConnectionSeedGenerated = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::set<size_t> result;
|
|
|
|
uint256 rnd = qwatchConnectionSeed;
|
|
|
|
for (size_t i = 0; i < connectionCount; i++) {
|
2019-07-09 07:59:57 +02:00
|
|
|
rnd = ::SerializeHash(std::make_pair(rnd, std::make_pair(llmqType, pindexQuorum->GetBlockHash())));
|
2018-05-24 16:14:55 +02:00
|
|
|
result.emplace(rnd.GetUint64(0) % memberCount);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
2018-11-23 15:42:09 +01:00
|
|
|
|
2019-01-15 15:35:26 +01:00
|
|
|
bool CLLMQUtils::IsQuorumActive(Consensus::LLMQType llmqType, const uint256& quorumHash)
|
|
|
|
{
|
|
|
|
auto& params = Params().GetConsensus().llmqs.at(llmqType);
|
|
|
|
|
|
|
|
// sig shares and recovered sigs are only accepted from recent/active quorums
|
|
|
|
// we allow one more active quorum as specified in consensus, as otherwise there is a small window where things could
|
|
|
|
// fail while we are on the brink of a new quorum
|
|
|
|
auto quorums = quorumManager->ScanQuorums(llmqType, (int)params.signingActiveQuorumCount + 1);
|
|
|
|
for (auto& q : quorums) {
|
2019-04-04 10:08:32 +02:00
|
|
|
if (q->qc.quorumHash == quorumHash) {
|
2019-01-15 15:35:26 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-15 20:55:01 +02:00
|
|
|
} // namespace llmq
|