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.
2020-03-19 23:46:56 +01:00
# include <llmq/quorums.h>
# include <llmq/quorums_utils.h>
2018-11-23 15:42:09 +01:00
2020-03-19 23:46:56 +01:00
# include <chainparams.h>
# include <random.h>
# 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
2020-03-16 10:54:59 +01:00
void CLLMQUtils : : EnsureQuorumConnections ( Consensus : : LLMQType llmqType , const CBlockIndex * pindexQuorum , const uint256 & myProTxHash , bool allowWatch )
{
auto members = GetAllQuorumMembers ( llmqType , pindexQuorum ) ;
bool isMember = std : : find_if ( members . begin ( ) , members . end ( ) , [ & ] ( const CDeterministicMNCPtr & dmn ) { return dmn - > proTxHash = = myProTxHash ; } ) ! = members . end ( ) ;
if ( ! isMember & & ! allowWatch ) {
return ;
}
std : : set < uint256 > connections ;
if ( isMember ) {
connections = CLLMQUtils : : GetQuorumConnections ( llmqType , pindexQuorum , myProTxHash ) ;
} else {
auto cindexes = CLLMQUtils : : CalcDeterministicWatchConnections ( llmqType , pindexQuorum , members . size ( ) , 1 ) ;
for ( auto idx : cindexes ) {
connections . emplace ( members [ idx ] - > proTxHash ) ;
}
}
if ( ! connections . empty ( ) ) {
2020-03-19 11:35:44 +01:00
if ( ! g_connman - > HasMasternodeQuorumNodes ( llmqType , pindexQuorum - > GetBlockHash ( ) ) & & LogAcceptCategory ( BCLog : : LLMQ ) ) {
2020-03-16 10:54:59 +01:00
auto mnList = deterministicMNManager - > GetListAtChainTip ( ) ;
std : : string debugMsg = strprintf ( " CLLMQUtils::%s -- adding masternodes quorum connections for quorum %s: \n " , __func__ , pindexQuorum - > GetBlockHash ( ) . ToString ( ) ) ;
for ( auto & c : connections ) {
auto dmn = mnList . GetValidMN ( c ) ;
if ( ! dmn ) {
debugMsg + = strprintf ( " %s (not in valid MN set anymore) \n " , c . ToString ( ) ) ;
} else {
debugMsg + = strprintf ( " %s (%s) \n " , c . ToString ( ) , dmn - > pdmnState - > addr . ToString ( false ) ) ;
}
}
LogPrint ( BCLog : : LLMQ , debugMsg . c_str ( ) ) ;
}
g_connman - > AddMasternodeQuorumNodes ( llmqType , pindexQuorum - > GetBlockHash ( ) , connections ) ;
}
}
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