b18f8cb77c
* Sort evo/* source files in Makefile.am * Keep track of proRegTxHash in CConnman::masternodeQuorumNodes map We will later need the proRegTxHash * Fix serialization of std::tuple with const rvalue elements Having serialization and deserialization in the same specialized template results in compilation failures due to the "if(for_read)" branch. * Implement MNAUTH message This allows masternodes to authenticate themself. * Protect fresh incoming connections for a second from eviction Give fresh connections some time to do the VERSION/VERACK handshake and an optional MNAUTH when it's a masternode. When an MNAUTH happened, the incoming connection is then forever protected against eviction. If a timeout of 1 second occurs or the first message after VERACK is not MNAUTH, the node is not protected anymore and becomes eligable for eviction. * Avoid connecting to masternodes if an incoming connection is from the same one Now that incoming connections from MNs authenticate them self, we can avoid connecting to the same MNs through intra-quorum connections. * Apply review suggestions
116 lines
4.0 KiB
C++
116 lines
4.0 KiB
C++
// Copyright (c) 2018-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 "quorums.h"
|
|
#include "quorums_utils.h"
|
|
|
|
#include "chainparams.h"
|
|
#include "random.h"
|
|
#include "validation.h"
|
|
|
|
namespace llmq
|
|
{
|
|
|
|
std::vector<CDeterministicMNCPtr> CLLMQUtils::GetAllQuorumMembers(Consensus::LLMQType llmqType, const uint256& blockHash)
|
|
{
|
|
auto& params = Params().GetConsensus().llmqs.at(llmqType);
|
|
auto allMns = deterministicMNManager->GetListForBlock(blockHash);
|
|
auto modifier = ::SerializeHash(std::make_pair((uint8_t)llmqType, blockHash));
|
|
return allMns.CalculateQuorum(params.size, modifier);
|
|
}
|
|
|
|
uint256 CLLMQUtils::BuildCommitmentHash(uint8_t llmqType, const uint256& blockHash, const std::vector<bool>& validMembers, const CBLSPublicKey& pubKey, const uint256& vvecHash)
|
|
{
|
|
CHashWriter hw(SER_NETWORK, 0);
|
|
hw << llmqType;
|
|
hw << blockHash;
|
|
hw << DYNBITSET(validMembers);
|
|
hw << pubKey;
|
|
hw << vvecHash;
|
|
return hw.GetHash();
|
|
}
|
|
|
|
uint256 CLLMQUtils::BuildSignHash(Consensus::LLMQType llmqType, const uint256& quorumHash, const uint256& id, const uint256& msgHash)
|
|
{
|
|
CHashWriter h(SER_GETHASH, 0);
|
|
h << (uint8_t)llmqType;
|
|
h << quorumHash;
|
|
h << id;
|
|
h << msgHash;
|
|
return h.GetHash();
|
|
}
|
|
|
|
std::map<CService, uint256> CLLMQUtils::GetQuorumConnections(Consensus::LLMQType llmqType, const uint256& blockHash, const uint256& forMember)
|
|
{
|
|
auto& params = Params().GetConsensus().llmqs.at(llmqType);
|
|
|
|
auto mns = GetAllQuorumMembers(llmqType, blockHash);
|
|
std::map<CService, uint256> result;
|
|
for (size_t i = 0; i < mns.size(); i++) {
|
|
auto& dmn = mns[i];
|
|
if (dmn->proTxHash == forMember) {
|
|
// 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
|
|
int gap = 1;
|
|
int gap_max = (int)mns.size() - 1;
|
|
int k = 0;
|
|
while ((gap_max >>= 1) || k <= 1) {
|
|
size_t idx = (i + gap) % mns.size();
|
|
auto& otherDmn = mns[idx];
|
|
if (otherDmn == dmn) {
|
|
continue;
|
|
}
|
|
result.emplace(otherDmn->pdmnState->addr, otherDmn->proTxHash);
|
|
gap <<= 1;
|
|
k++;
|
|
}
|
|
// there can be no two members with the same proTxHash, so return early
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
std::set<size_t> CLLMQUtils::CalcDeterministicWatchConnections(Consensus::LLMQType llmqType, const uint256& blockHash, size_t memberCount, size_t connectionCount)
|
|
{
|
|
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++) {
|
|
rnd = ::SerializeHash(std::make_pair(rnd, std::make_pair((uint8_t)llmqType, blockHash)));
|
|
result.emplace(rnd.GetUint64(0) % memberCount);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
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) {
|
|
if (q->quorumHash == quorumHash) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
}
|