2022-06-08 01:36:46 +02:00
// Copyright (c) 2018-2022 The Dash Core developers
2018-05-24 16:14:55 +02:00
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2021-10-02 19:32:24 +02:00
# include <llmq/dkgsessionhandler.h>
2021-04-16 05:41:16 +02:00
2021-10-02 19:32:24 +02:00
# include <llmq/commitment.h>
# include <llmq/dkgsession.h>
# include <llmq/blockprocessor.h>
# include <llmq/debug.h>
# include <llmq/utils.h>
2018-05-24 16:14:55 +02:00
2021-04-16 05:41:16 +02:00
# include <evo/deterministicmns.h>
2023-12-04 18:58:13 +01:00
# include <deploymentstatus.h>
2021-10-01 21:19:08 +02:00
# include <masternode/node.h>
2020-03-19 23:46:56 +01:00
# include <chainparams.h>
# include <net_processing.h>
2022-04-17 12:52:51 +02:00
# include <validation.h>
2023-08-26 11:50:37 +02:00
# include <util/thread.h>
2023-02-20 11:12:12 +01:00
# include <util/underlying.h>
2018-05-24 16:14:55 +02:00
namespace llmq
{
2023-08-23 19:11:26 +02:00
CDKGSessionHandler : : CDKGSessionHandler ( CBLSWorker & _blsWorker , CChainState & chainstate , CConnman & _connman , CDKGDebugManager & _dkgDebugManager ,
CDKGSessionManager & _dkgManager , CQuorumBlockProcessor & _quorumBlockProcessor ,
const Consensus : : LLMQParams & _params , const std : : unique_ptr < PeerManager > & peerman , int _quorumIndex ) :
2023-02-20 11:12:12 +01:00
blsWorker ( _blsWorker ) ,
2023-08-23 19:11:26 +02:00
m_chainstate ( chainstate ) ,
connman ( _connman ) ,
2023-02-20 11:12:12 +01:00
dkgDebugManager ( _dkgDebugManager ) ,
2023-08-23 19:11:26 +02:00
dkgManager ( _dkgManager ) ,
2023-02-20 11:12:12 +01:00
quorumBlockProcessor ( _quorumBlockProcessor ) ,
2023-08-23 19:11:26 +02:00
params ( _params ) ,
2023-04-28 07:17:42 +02:00
m_peerman ( peerman ) ,
2023-08-23 19:11:26 +02:00
quorumIndex ( _quorumIndex ) ,
2023-02-20 11:12:12 +01:00
curSession ( std : : make_unique < CDKGSession > ( _params , _blsWorker , _dkgManager , _dkgDebugManager , _connman ) ) ,
pendingContributions ( ( size_t ) _params . size * 2 , MSG_QUORUM_CONTRIB ) , // we allow size*2 messages as we need to make sure we see bad behavior (double messages)
pendingComplaints ( ( size_t ) _params . size * 2 , MSG_QUORUM_COMPLAINT ) ,
pendingJustifications ( ( size_t ) _params . size * 2 , MSG_QUORUM_JUSTIFICATION ) ,
pendingPrematureCommitments ( ( size_t ) _params . size * 2 , MSG_QUORUM_PREMATURE_COMMITMENT )
{
if ( params . type = = Consensus : : LLMQType : : LLMQ_NONE ) {
throw std : : runtime_error ( " Can't initialize CDKGSessionHandler with LLMQ_NONE type. " ) ;
}
}
2018-05-24 16:14:55 +02:00
void CDKGPendingMessages : : PushPendingMessage ( NodeId from , CDataStream & vRecv )
{
// this will also consume the data, even if we bail out early
auto pm = std : : make_shared < CDataStream > ( std : : move ( vRecv ) ) ;
CHashWriter hw ( SER_GETHASH , 0 ) ;
2023-09-10 21:23:19 +02:00
hw . write ( reinterpret_cast < const char * > ( pm - > data ( ) ) , pm - > size ( ) ) ;
2018-05-24 16:14:55 +02:00
uint256 hash = hw . GetHash ( ) ;
2020-10-28 20:02:05 +01:00
if ( from ! = - 1 ) {
LOCK ( cs_main ) ;
EraseObjectRequest ( from , CInv ( invType , hash ) ) ;
}
LOCK ( cs ) ;
if ( messagesPerNode [ from ] > = maxMessagesPerNode ) {
// TODO ban?
LogPrint ( BCLog : : LLMQ_DKG , " CDKGPendingMessages::%s -- too many messages, peer=%d \n " , __func__ , from ) ;
return ;
}
messagesPerNode [ from ] + + ;
2018-05-24 16:14:55 +02:00
if ( ! seenMessages . emplace ( hash ) . second ) {
2019-12-24 20:35:21 +01:00
LogPrint ( BCLog : : LLMQ_DKG , " CDKGPendingMessages::%s -- already seen %s, peer=%d \n " , __func__ , hash . ToString ( ) , from ) ;
2018-05-24 16:14:55 +02:00
return ;
}
pendingMessages . emplace_back ( std : : make_pair ( from , std : : move ( pm ) ) ) ;
}
std : : list < CDKGPendingMessages : : BinaryMessage > CDKGPendingMessages : : PopPendingMessages ( size_t maxCount )
{
LOCK ( cs ) ;
std : : list < BinaryMessage > ret ;
while ( ! pendingMessages . empty ( ) & & ret . size ( ) < maxCount ) {
ret . emplace_back ( std : : move ( pendingMessages . front ( ) ) ) ;
pendingMessages . pop_front ( ) ;
}
2021-06-26 15:10:53 +02:00
return ret ;
2018-05-24 16:14:55 +02:00
}
bool CDKGPendingMessages : : HasSeen ( const uint256 & hash ) const
{
LOCK ( cs ) ;
return seenMessages . count ( hash ) ! = 0 ;
}
void CDKGPendingMessages : : Clear ( )
{
LOCK ( cs ) ;
pendingMessages . clear ( ) ;
messagesPerNode . clear ( ) ;
seenMessages . clear ( ) ;
}
//////
2019-04-30 14:48:21 +02:00
void CDKGSessionHandler : : UpdatedBlockTip ( const CBlockIndex * pindexNew )
2018-05-24 16:14:55 +02:00
{
2022-04-16 16:46:04 +02:00
//AssertLockNotHeld(cs_main);
//Indexed quorums (greater than 0) are enabled with Quorum Rotation
2023-03-13 17:11:17 +01:00
if ( quorumIndex > 0 & & ! utils : : IsQuorumRotationEnabled ( params , pindexNew ) ) {
2022-04-16 16:46:04 +02:00
return ;
}
2018-05-24 16:14:55 +02:00
LOCK ( cs ) ;
2022-04-16 16:46:04 +02:00
int quorumStageInt = ( pindexNew - > nHeight - quorumIndex ) % params . dkgInterval ;
2021-10-26 18:08:38 +02:00
const CBlockIndex * pQuorumBaseBlockIndex = pindexNew - > GetAncestor ( pindexNew - > nHeight - quorumStageInt ) ;
2018-05-24 16:14:55 +02:00
2019-12-31 11:01:01 +01:00
currentHeight = pindexNew - > nHeight ;
2021-10-26 18:08:38 +02:00
quorumHash = pQuorumBaseBlockIndex - > GetBlockHash ( ) ;
2018-05-24 16:14:55 +02:00
2019-01-22 14:33:42 +01:00
bool fNewPhase = ( quorumStageInt % params . dkgPhaseBlocks ) = = 0 ;
2019-01-23 15:02:56 +01:00
int phaseInt = quorumStageInt / params . dkgPhaseBlocks + 1 ;
2020-03-26 13:25:01 +01:00
QuorumPhase oldPhase = phase ;
2023-02-20 11:12:12 +01:00
if ( fNewPhase & & phaseInt > = ToUnderlying ( QuorumPhase : : Initialized ) & & phaseInt < = ToUnderlying ( QuorumPhase : : Idle ) ) {
2019-01-22 14:33:42 +01:00
phase = static_cast < QuorumPhase > ( phaseInt ) ;
2018-05-24 16:14:55 +02:00
}
2020-03-26 13:25:01 +01:00
2022-06-27 12:02:46 +02:00
LogPrint ( BCLog : : LLMQ_DKG , " CDKGSessionHandler::%s -- %s qi[%d] currentHeight=%d, pQuorumBaseBlockIndex->nHeight=%d, oldPhase=%d, newPhase=%d \n " , __func__ ,
2023-02-20 11:12:12 +01:00
params . name , quorumIndex , currentHeight , pQuorumBaseBlockIndex - > nHeight , ToUnderlying ( oldPhase ) , ToUnderlying ( phase ) ) ;
2018-05-24 16:14:55 +02:00
}
2023-01-20 14:53:36 +01:00
void CDKGSessionHandler : : ProcessMessage ( const CNode & pfrom , const std : : string & msg_type , CDataStream & vRecv )
2018-05-24 16:14:55 +02:00
{
// We don't handle messages in the calling thread as deserialization/processing of these would block everything
2022-04-18 18:47:26 +02:00
if ( msg_type = = NetMsgType : : QCONTRIB ) {
2023-01-19 18:33:10 +01:00
pendingContributions . PushPendingMessage ( pfrom . GetId ( ) , vRecv ) ;
2022-04-18 18:47:26 +02:00
} else if ( msg_type = = NetMsgType : : QCOMPLAINT ) {
2023-01-19 18:33:10 +01:00
pendingComplaints . PushPendingMessage ( pfrom . GetId ( ) , vRecv ) ;
2022-04-18 18:47:26 +02:00
} else if ( msg_type = = NetMsgType : : QJUSTIFICATION ) {
2023-01-19 18:33:10 +01:00
pendingJustifications . PushPendingMessage ( pfrom . GetId ( ) , vRecv ) ;
2022-04-18 18:47:26 +02:00
} else if ( msg_type = = NetMsgType : : QPCOMMITMENT ) {
2023-01-19 18:33:10 +01:00
pendingPrematureCommitments . PushPendingMessage ( pfrom . GetId ( ) , vRecv ) ;
2018-05-24 16:14:55 +02:00
}
}
2020-07-16 22:30:59 +02:00
void CDKGSessionHandler : : StartThread ( )
{
if ( phaseHandlerThread . joinable ( ) ) {
throw std : : runtime_error ( " Tried to start an already started CDKGSessionHandler thread. " ) ;
}
2023-08-26 11:50:37 +02:00
m_thread_name = strprintf ( " llmq-%d-%d " , ToUnderlying ( params . type ) , quorumIndex ) ;
phaseHandlerThread = std : : thread ( util : : TraceThread , m_thread_name . c_str ( ) , [ this ] { PhaseHandlerThread ( ) ; } ) ;
2020-07-16 22:30:59 +02:00
}
void CDKGSessionHandler : : StopThread ( )
{
stopRequested = true ;
if ( phaseHandlerThread . joinable ( ) ) {
phaseHandlerThread . join ( ) ;
}
}
2021-10-26 18:08:38 +02:00
bool CDKGSessionHandler : : InitNewQuorum ( const CBlockIndex * pQuorumBaseBlockIndex )
2018-05-24 16:14:55 +02:00
{
2022-09-22 13:14:48 +02:00
curSession = std : : make_unique < CDKGSession > ( params , blsWorker , dkgManager , dkgDebugManager , connman ) ;
2018-05-24 16:14:55 +02:00
2023-12-04 18:58:13 +01:00
if ( ! DeploymentDIP0003Enforced ( pQuorumBaseBlockIndex - > nHeight , Params ( ) . GetConsensus ( ) ) ) {
2018-05-24 16:14:55 +02:00
return false ;
}
2022-08-02 19:14:25 +02:00
auto mns = utils : : GetAllQuorumMembers ( params . type , pQuorumBaseBlockIndex ) ;
2022-04-16 16:46:04 +02:00
if ( ! curSession - > Init ( pQuorumBaseBlockIndex , mns , WITH_LOCK ( activeMasternodeInfoCs , return activeMasternodeInfo . proTxHash ) , quorumIndex ) ) {
2022-06-27 12:02:46 +02:00
LogPrintf ( " CDKGSessionManager::%s -- height[%d] quorum initialization failed for %s qi[%d] mns[%d] \n " , __func__ , pQuorumBaseBlockIndex - > nHeight , curSession - > params . name , quorumIndex , mns . size ( ) ) ;
2018-05-24 16:14:55 +02:00
return false ;
}
2022-07-18 22:55:47 +02:00
LogPrintf ( " CDKGSessionManager::%s -- height[%d] quorum initialization OK for %s qi[%d] \n " , __func__ , pQuorumBaseBlockIndex - > nHeight , curSession - > params . name , quorumIndex ) ;
2018-05-24 16:14:55 +02:00
return true ;
}
2019-01-11 10:00:40 +01:00
std : : pair < QuorumPhase , uint256 > CDKGSessionHandler : : GetPhaseAndQuorumHash ( ) const
2018-05-24 16:14:55 +02:00
{
LOCK ( cs ) ;
return std : : make_pair ( phase , quorumHash ) ;
}
class AbortPhaseException : public std : : exception {
} ;
2022-03-13 21:56:31 +01:00
void CDKGSessionHandler : : WaitForNextPhase ( std : : optional < QuorumPhase > curPhase ,
2018-05-24 16:14:55 +02:00
QuorumPhase nextPhase ,
2019-01-22 14:33:42 +01:00
const uint256 & expectedQuorumHash ,
2022-03-13 21:56:31 +01:00
const WhileWaitFunc & shouldNotWait ) const
2018-05-24 16:14:55 +02:00
{
2023-02-20 11:12:12 +01:00
LogPrint ( BCLog : : LLMQ_DKG , " CDKGSessionManager::%s -- %s qi[%d] - starting, curPhase=%d, nextPhase=%d \n " , __func__ , params . name , quorumIndex , curPhase . has_value ( ) ? ToUnderlying ( * curPhase ) : - 1 , ToUnderlying ( nextPhase ) ) ;
2020-03-26 13:25:01 +01:00
2018-05-24 16:14:55 +02:00
while ( true ) {
2021-03-29 20:03:17 +02:00
if ( stopRequested ) {
2022-06-27 12:02:46 +02:00
LogPrint ( BCLog : : LLMQ_DKG , " CDKGSessionManager::%s -- %s qi[%d] - aborting due to stop/shutdown requested \n " , __func__ , params . name , quorumIndex ) ;
2018-05-24 16:14:55 +02:00
throw AbortPhaseException ( ) ;
}
2022-03-13 21:56:31 +01:00
auto [ _phase , _quorumHash ] = GetPhaseAndQuorumHash ( ) ;
if ( ! expectedQuorumHash . IsNull ( ) & & _quorumHash ! = expectedQuorumHash ) {
2022-06-27 12:02:46 +02:00
LogPrint ( BCLog : : LLMQ_DKG , " CDKGSessionManager::%s -- %s qi[%d] - aborting due unexpected expectedQuorumHash change \n " , __func__ , params . name , quorumIndex ) ;
2018-05-24 16:14:55 +02:00
throw AbortPhaseException ( ) ;
}
2022-03-13 21:56:31 +01:00
if ( _phase = = nextPhase ) {
2019-01-30 14:05:22 +01:00
break ;
2018-05-24 16:14:55 +02:00
}
2022-03-13 21:56:31 +01:00
if ( curPhase . has_value ( ) & & _phase ! = curPhase ) {
2023-02-20 11:12:12 +01:00
LogPrint ( BCLog : : LLMQ_DKG , " CDKGSessionManager::%s -- %s qi[%d] - aborting due unexpected phase change, _phase=%d, curPhase=%d \n " , __func__ , params . name , quorumIndex , ToUnderlying ( _phase ) , curPhase . has_value ( ) ? ToUnderlying ( * curPhase ) : - 1 ) ;
2018-05-24 16:14:55 +02:00
throw AbortPhaseException ( ) ;
}
2022-03-13 21:56:31 +01:00
if ( ! shouldNotWait ( ) ) {
2021-07-13 11:31:17 +02:00
UninterruptibleSleep ( std : : chrono : : milliseconds { 100 } ) ;
2018-05-24 16:14:55 +02:00
}
}
2019-01-30 14:05:22 +01:00
2023-02-20 11:12:12 +01:00
LogPrint ( BCLog : : LLMQ_DKG , " CDKGSessionManager::%s -- %s qi[%d] - done, curPhase=%d, nextPhase=%d \n " , __func__ , params . name , quorumIndex , curPhase . has_value ( ) ? ToUnderlying ( * curPhase ) : - 1 , ToUnderlying ( nextPhase ) ) ;
2020-03-26 13:25:01 +01:00
2022-03-13 21:56:31 +01:00
if ( nextPhase = = QuorumPhase : : Initialized ) {
2022-09-22 13:14:48 +02:00
dkgDebugManager . ResetLocalSessionStatus ( params . type , quorumIndex ) ;
2019-02-01 08:49:01 +01:00
} else {
2022-09-22 13:14:48 +02:00
dkgDebugManager . UpdateLocalSessionStatus ( params . type , quorumIndex , [ & ] ( CDKGDebugSessionStatus & status ) {
2023-02-20 11:12:12 +01:00
bool changed = status . phase ! = nextPhase ;
status . phase = nextPhase ;
2019-02-01 08:49:01 +01:00
return changed ;
} ) ;
2019-01-30 14:05:22 +01:00
}
2018-05-24 16:14:55 +02:00
}
2021-06-26 15:10:53 +02:00
void CDKGSessionHandler : : WaitForNewQuorum ( const uint256 & oldQuorumHash ) const
2018-05-24 16:14:55 +02:00
{
2022-06-27 12:02:46 +02:00
LogPrint ( BCLog : : LLMQ_DKG , " CDKGSessionManager::%s -- %s qi[%d]- starting \n " , __func__ , params . name , quorumIndex ) ;
2020-03-26 13:25:01 +01:00
2018-05-24 16:14:55 +02:00
while ( true ) {
2021-03-29 20:03:17 +02:00
if ( stopRequested ) {
2022-06-27 12:02:46 +02:00
LogPrint ( BCLog : : LLMQ_DKG , " CDKGSessionManager::%s -- %s qi[%d] - aborting due to stop/shutdown requested \n " , __func__ , params . name , quorumIndex ) ;
2018-05-24 16:14:55 +02:00
throw AbortPhaseException ( ) ;
}
2022-06-27 12:02:46 +02:00
auto [ _ , _quorumHash ] = GetPhaseAndQuorumHash ( ) ;
if ( _quorumHash ! = oldQuorumHash ) {
2020-03-26 13:25:01 +01:00
break ;
2018-05-24 16:14:55 +02:00
}
2021-07-13 11:31:17 +02:00
UninterruptibleSleep ( std : : chrono : : milliseconds { 100 } ) ;
2018-05-24 16:14:55 +02:00
}
2020-03-26 13:25:01 +01:00
2022-06-27 12:02:46 +02:00
LogPrint ( BCLog : : LLMQ_DKG , " CDKGSessionManager::%s -- %s qi[%d] - done \n " , __func__ , params . name , quorumIndex ) ;
2018-05-24 16:14:55 +02:00
}
2019-01-10 07:07:58 +01:00
// Sleep some time to not fully overload the whole network
void CDKGSessionHandler : : SleepBeforePhase ( QuorumPhase curPhase ,
2019-01-22 14:33:42 +01:00
const uint256 & expectedQuorumHash ,
2019-01-10 07:07:58 +01:00
double randomSleepFactor ,
2021-09-08 00:33:02 +02:00
const WhileWaitFunc & runWhileWaiting ) const
2018-05-24 16:14:55 +02:00
{
2019-12-06 10:10:01 +01:00
if ( ! curSession - > AreWeMember ( ) ) {
// Non-members do not participate and do not create any network load, no need to sleep.
return ;
}
if ( Params ( ) . MineBlocksOnDemand ( ) ) {
// On regtest, blocks can be mined on demand without any significant time passing between these.
// We shouldn't wait before phases in this case.
return ;
}
2019-12-31 11:01:01 +01:00
// Two blocks can come very close to each other, this happens pretty regularly. We don't want to be
// left behind and marked as a bad member. This means that we should not count the last block of the
// phase as a safe one to keep sleeping, that's why we calculate the phase sleep time as a time of
// the full phase minus one block here.
double phaseSleepTime = ( params . dkgPhaseBlocks - 1 ) * Params ( ) . GetConsensus ( ) . nPowTargetSpacing * 1000 ;
// Expected phase sleep time per member
double phaseSleepTimePerMember = phaseSleepTime / params . size ;
2019-01-10 07:07:58 +01:00
// Don't expect perfect block times and thus reduce the phase time to be on the secure side (caller chooses factor)
2019-12-31 11:01:01 +01:00
double adjustedPhaseSleepTimePerMember = phaseSleepTimePerMember * randomSleepFactor ;
2019-01-10 07:07:58 +01:00
2021-11-29 06:12:09 +01:00
int64_t sleepTime = ( int64_t ) ( adjustedPhaseSleepTimePerMember * curSession - > GetMyMemberIndex ( ) . value_or ( 0 ) ) ;
2019-01-10 07:07:58 +01:00
int64_t endTime = GetTimeMillis ( ) + sleepTime ;
2019-12-31 11:01:01 +01:00
int heightTmp { - 1 } ;
int heightStart { - 1 } ;
2022-07-18 22:55:47 +02:00
heightTmp = heightStart = WITH_LOCK ( cs , return currentHeight ) ;
2020-03-26 13:25:01 +01:00
2023-02-20 11:12:12 +01:00
LogPrint ( BCLog : : LLMQ_DKG , " CDKGSessionManager::%s -- %s qi[%d] - starting sleep for %d ms, curPhase=%d \n " , __func__ , params . name , quorumIndex , sleepTime , ToUnderlying ( curPhase ) ) ;
2020-03-26 13:25:01 +01:00
2018-05-24 16:14:55 +02:00
while ( GetTimeMillis ( ) < endTime ) {
2021-03-29 20:03:17 +02:00
if ( stopRequested ) {
2022-06-27 12:02:46 +02:00
LogPrint ( BCLog : : LLMQ_DKG , " CDKGSessionManager::%s -- %s qi[%d] - aborting due to stop/shutdown requested \n " , __func__ , params . name , quorumIndex ) ;
2018-05-24 16:14:55 +02:00
throw AbortPhaseException ( ) ;
}
2019-12-31 11:01:01 +01:00
{
LOCK ( cs ) ;
if ( currentHeight > heightTmp ) {
// New block(s) just came in
int64_t expectedBlockTime = ( currentHeight - heightStart ) * Params ( ) . GetConsensus ( ) . nPowTargetSpacing * 1000 ;
if ( expectedBlockTime > sleepTime ) {
// Blocks came faster than we expected, jump into the phase func asap
break ;
}
heightTmp = currentHeight ;
}
if ( phase ! = curPhase | | quorumHash ! = expectedQuorumHash ) {
2020-08-09 23:35:02 +02:00
// Something went wrong and/or we missed quite a few blocks and it's just too late now
2022-06-27 12:02:46 +02:00
LogPrint ( BCLog : : LLMQ_DKG , " CDKGSessionManager::%s -- %s qi[%d] - aborting due unexpected phase/expectedQuorumHash change \n " , __func__ , params . name , quorumIndex ) ;
2019-12-31 11:01:01 +01:00
throw AbortPhaseException ( ) ;
}
2018-05-24 16:14:55 +02:00
}
if ( ! runWhileWaiting ( ) ) {
2021-07-13 11:31:17 +02:00
UninterruptibleSleep ( std : : chrono : : milliseconds { 100 } ) ;
2018-05-24 16:14:55 +02:00
}
}
2020-03-26 13:25:01 +01:00
2023-02-20 11:12:12 +01:00
LogPrint ( BCLog : : LLMQ_DKG , " CDKGSessionManager::%s -- %s qi[%d] - done, curPhase=%d \n " , __func__ , params . name , quorumIndex , ToUnderlying ( curPhase ) ) ;
2018-05-24 16:14:55 +02:00
}
void CDKGSessionHandler : : HandlePhase ( QuorumPhase curPhase ,
QuorumPhase nextPhase ,
2019-01-22 14:33:42 +01:00
const uint256 & expectedQuorumHash ,
2018-05-24 16:14:55 +02:00
double randomSleepFactor ,
const StartPhaseFunc & startPhaseFunc ,
const WhileWaitFunc & runWhileWaiting )
{
2023-02-20 11:12:12 +01:00
LogPrint ( BCLog : : LLMQ_DKG , " CDKGSessionManager::%s -- %s qi[%d] - starting, curPhase=%d, nextPhase=%d \n " , __func__ , params . name , quorumIndex , ToUnderlying ( curPhase ) , ToUnderlying ( nextPhase ) ) ;
2020-03-26 13:25:01 +01:00
2019-01-10 07:07:58 +01:00
SleepBeforePhase ( curPhase , expectedQuorumHash , randomSleepFactor , runWhileWaiting ) ;
2018-05-24 16:14:55 +02:00
startPhaseFunc ( ) ;
WaitForNextPhase ( curPhase , nextPhase , expectedQuorumHash , runWhileWaiting ) ;
2020-03-26 13:25:01 +01:00
2023-02-20 11:12:12 +01:00
LogPrint ( BCLog : : LLMQ_DKG , " CDKGSessionManager::%s -- %s qi[%d] - done, curPhase=%d, nextPhase=%d \n " , __func__ , params . name , quorumIndex , ToUnderlying ( curPhase ) , ToUnderlying ( nextPhase ) ) ;
2018-05-24 16:14:55 +02:00
}
// returns a set of NodeIds which sent invalid messages
template < typename Message >
std : : set < NodeId > BatchVerifyMessageSigs ( CDKGSession & session , const std : : vector < std : : pair < NodeId , std : : shared_ptr < Message > > > & messages )
{
if ( messages . empty ( ) ) {
return { } ;
}
std : : set < NodeId > ret ;
bool revertToSingleVerification = false ;
CBLSSignature aggSig ;
std : : vector < CBLSPublicKey > pubKeys ;
std : : vector < uint256 > messageHashes ;
std : : set < uint256 > messageHashesSet ;
pubKeys . reserve ( messages . size ( ) ) ;
messageHashes . reserve ( messages . size ( ) ) ;
bool first = true ;
for ( const auto & p : messages ) {
const auto & msg = * p . second ;
auto member = session . GetMember ( msg . proTxHash ) ;
if ( ! member ) {
// should not happen as it was verified before
ret . emplace ( p . first ) ;
continue ;
}
if ( first ) {
aggSig = msg . sig ;
} else {
aggSig . AggregateInsecure ( msg . sig ) ;
}
first = false ;
auto msgHash = msg . GetSignHash ( ) ;
if ( ! messageHashesSet . emplace ( msgHash ) . second ) {
// can only happen in 2 cases:
// 1. Someone sent us the same message twice but with differing signature, meaning that at least one of them
// must be invalid. In this case, we'd have to revert to single message verification nevertheless
// 2. Someone managed to find a way to create two different binary representations of a message that deserializes
// to the same object representation. This would be some form of malleability. However, this shouldn't be
// possible as only deterministic/unique BLS signatures and very simple data types are involved
revertToSingleVerification = true ;
break ;
}
2019-06-13 11:01:26 +02:00
pubKeys . emplace_back ( member - > dmn - > pdmnState - > pubKeyOperator . Get ( ) ) ;
2018-05-24 16:14:55 +02:00
messageHashes . emplace_back ( msgHash ) ;
}
if ( ! revertToSingleVerification ) {
2021-11-30 06:03:08 +01:00
if ( aggSig . VerifyInsecureAggregated ( pubKeys , messageHashes ) ) {
2018-05-24 16:14:55 +02:00
// all good
return ret ;
}
// are all messages from the same node?
2021-11-30 06:03:08 +01:00
bool nodeIdsAllSame = std : : adjacent_find ( messages . begin ( ) , messages . end ( ) , [ ] ( const auto & first , const auto & second ) {
return first . first ! = second . first ;
} ) = = messages . end ( ) ;
2018-05-24 16:14:55 +02:00
// if yes, take a short path and return a set with only him
if ( nodeIdsAllSame ) {
2021-11-30 06:03:08 +01:00
ret . emplace ( messages [ 0 ] . first ) ;
2018-05-24 16:14:55 +02:00
return ret ;
}
// different nodes, let's figure out who are the bad ones
}
for ( const auto & p : messages ) {
if ( ret . count ( p . first ) ) {
continue ;
}
const auto & msg = * p . second ;
auto member = session . GetMember ( msg . proTxHash ) ;
2019-06-13 11:01:26 +02:00
bool valid = msg . sig . VerifyInsecure ( member - > dmn - > pdmnState - > pubKeyOperator . Get ( ) , msg . GetSignHash ( ) ) ;
2018-05-24 16:14:55 +02:00
if ( ! valid ) {
ret . emplace ( p . first ) ;
}
}
return ret ;
}
2020-04-07 13:25:29 +02:00
template < typename Message , int MessageType >
2023-04-28 07:17:42 +02:00
bool ProcessPendingMessageBatch ( CDKGSession & session , PeerManager & peerman , CDKGPendingMessages & pendingMessages , size_t maxCount )
2018-05-24 16:14:55 +02:00
{
auto msgs = pendingMessages . PopAndDeserializeMessages < Message > ( maxCount ) ;
if ( msgs . empty ( ) ) {
return false ;
}
std : : vector < std : : pair < NodeId , std : : shared_ptr < Message > > > preverifiedMessages ;
preverifiedMessages . reserve ( msgs . size ( ) ) ;
for ( const auto & p : msgs ) {
2021-01-14 20:42:08 +01:00
const NodeId & nodeId = p . first ;
2018-05-24 16:14:55 +02:00
if ( ! p . second ) {
2021-01-14 20:42:08 +01:00
LogPrint ( BCLog : : LLMQ_DKG , " %s -- failed to deserialize message, peer=%d \n " , __func__ , nodeId ) ;
2018-05-24 16:14:55 +02:00
{
2023-04-28 07:17:42 +02:00
peerman . Misbehaving ( nodeId , 100 ) ;
2018-05-24 16:14:55 +02:00
}
continue ;
}
bool ban = false ;
2021-01-14 20:42:08 +01:00
if ( ! session . PreVerifyMessage ( * p . second , ban ) ) {
2018-05-24 16:14:55 +02:00
if ( ban ) {
2021-01-14 20:42:08 +01:00
LogPrint ( BCLog : : LLMQ_DKG , " %s -- banning node due to failed preverification, peer=%d \n " , __func__ , nodeId ) ;
2018-05-24 16:14:55 +02:00
{
2023-04-28 07:17:42 +02:00
peerman . Misbehaving ( nodeId , 100 ) ;
2018-05-24 16:14:55 +02:00
}
}
2021-01-14 20:42:08 +01:00
LogPrint ( BCLog : : LLMQ_DKG , " %s -- skipping message due to failed preverification, peer=%d \n " , __func__ , nodeId ) ;
2018-05-24 16:14:55 +02:00
continue ;
}
preverifiedMessages . emplace_back ( p ) ;
}
if ( preverifiedMessages . empty ( ) ) {
return true ;
}
auto badNodes = BatchVerifyMessageSigs ( session , preverifiedMessages ) ;
if ( ! badNodes . empty ( ) ) {
LOCK ( cs_main ) ;
for ( auto nodeId : badNodes ) {
2020-01-28 11:04:47 +01:00
LogPrint ( BCLog : : LLMQ_DKG , " %s -- failed to verify signature, peer=%d \n " , __func__ , nodeId ) ;
2023-04-28 07:17:42 +02:00
peerman . Misbehaving ( nodeId , 100 ) ;
2018-05-24 16:14:55 +02:00
}
}
2021-01-14 20:42:08 +01:00
for ( const auto & p : preverifiedMessages ) {
const NodeId & nodeId = p . first ;
2018-05-24 16:14:55 +02:00
if ( badNodes . count ( nodeId ) ) {
continue ;
}
bool ban = false ;
2021-01-14 20:42:08 +01:00
session . ReceiveMessage ( * p . second , ban ) ;
2018-05-24 16:14:55 +02:00
if ( ban ) {
2020-01-28 11:04:47 +01:00
LogPrint ( BCLog : : LLMQ_DKG , " %s -- banning node after ReceiveMessage failed, peer=%d \n " , __func__ , nodeId ) ;
2023-04-28 07:17:42 +02:00
peerman . Misbehaving ( nodeId , 100 ) ;
2018-05-24 16:14:55 +02:00
badNodes . emplace ( nodeId ) ;
}
}
return true ;
}
void CDKGSessionHandler : : HandleDKGRound ( )
{
uint256 curQuorumHash ;
2022-03-13 21:56:31 +01:00
WaitForNextPhase ( std : : nullopt , QuorumPhase : : Initialized ) ;
2018-05-24 16:14:55 +02:00
{
LOCK ( cs ) ;
pendingContributions . Clear ( ) ;
pendingComplaints . Clear ( ) ;
pendingJustifications . Clear ( ) ;
pendingPrematureCommitments . Clear ( ) ;
2019-01-22 14:33:42 +01:00
curQuorumHash = quorumHash ;
2018-05-24 16:14:55 +02:00
}
2023-08-23 19:11:26 +02:00
const CBlockIndex * pQuorumBaseBlockIndex = WITH_LOCK ( cs_main , return m_chainstate . m_blockman . LookupBlockIndex ( curQuorumHash ) ) ;
2019-07-09 07:59:57 +02:00
2021-10-26 18:08:38 +02:00
if ( ! InitNewQuorum ( pQuorumBaseBlockIndex ) ) {
2018-05-24 16:14:55 +02:00
// should actually never happen
WaitForNewQuorum ( curQuorumHash ) ;
throw AbortPhaseException ( ) ;
}
2022-09-22 13:14:48 +02:00
dkgDebugManager . UpdateLocalSessionStatus ( params . type , quorumIndex , [ & ] ( CDKGDebugSessionStatus & status ) {
2023-02-20 11:12:12 +01:00
bool changed = status . phase ! = QuorumPhase : : Initialized ;
status . phase = QuorumPhase : : Initialized ;
2019-02-01 08:49:01 +01:00
return changed ;
} ) ;
2022-08-02 19:14:25 +02:00
utils : : EnsureQuorumConnections ( params , pQuorumBaseBlockIndex , connman , curSession - > myProTxHash ) ;
2021-01-11 04:23:01 +01:00
if ( curSession - > AreWeMember ( ) ) {
2022-08-02 19:14:25 +02:00
utils : : AddQuorumProbeConnections ( params , pQuorumBaseBlockIndex , connman , curSession - > myProTxHash ) ;
2020-03-17 10:04:31 +01:00
}
2018-05-24 16:14:55 +02:00
2022-03-13 21:56:31 +01:00
WaitForNextPhase ( QuorumPhase : : Initialized , QuorumPhase : : Contribute , curQuorumHash ) ;
2018-05-24 16:14:55 +02:00
// Contribute
auto fContributeStart = [ this ] ( ) {
2019-01-11 13:03:25 +01:00
curSession - > Contribute ( pendingContributions ) ;
2018-05-24 16:14:55 +02:00
} ;
auto fContributeWait = [ this ] {
2023-04-28 07:17:42 +02:00
return ProcessPendingMessageBatch < CDKGContribution , MSG_QUORUM_CONTRIB > ( * curSession , * m_peerman , pendingContributions , 8 ) ;
2018-05-24 16:14:55 +02:00
} ;
2022-03-13 21:56:31 +01:00
HandlePhase ( QuorumPhase : : Contribute , QuorumPhase : : Complain , curQuorumHash , 0.05 , fContributeStart , fContributeWait ) ;
2018-05-24 16:14:55 +02:00
// Complain
auto fComplainStart = [ this ] ( ) {
2019-01-11 13:03:25 +01:00
curSession - > VerifyAndComplain ( pendingComplaints ) ;
2018-05-24 16:14:55 +02:00
} ;
auto fComplainWait = [ this ] {
2023-04-28 07:17:42 +02:00
return ProcessPendingMessageBatch < CDKGComplaint , MSG_QUORUM_COMPLAINT > ( * curSession , * m_peerman , pendingComplaints , 8 ) ;
2018-05-24 16:14:55 +02:00
} ;
2022-03-13 21:56:31 +01:00
HandlePhase ( QuorumPhase : : Complain , QuorumPhase : : Justify , curQuorumHash , 0.05 , fComplainStart , fComplainWait ) ;
2018-05-24 16:14:55 +02:00
// Justify
auto fJustifyStart = [ this ] ( ) {
2019-01-11 13:03:25 +01:00
curSession - > VerifyAndJustify ( pendingJustifications ) ;
2018-05-24 16:14:55 +02:00
} ;
auto fJustifyWait = [ this ] {
2023-04-28 07:17:42 +02:00
return ProcessPendingMessageBatch < CDKGJustification , MSG_QUORUM_JUSTIFICATION > ( * curSession , * m_peerman , pendingJustifications , 8 ) ;
2018-05-24 16:14:55 +02:00
} ;
2022-03-13 21:56:31 +01:00
HandlePhase ( QuorumPhase : : Justify , QuorumPhase : : Commit , curQuorumHash , 0.05 , fJustifyStart , fJustifyWait ) ;
2018-05-24 16:14:55 +02:00
// Commit
auto fCommitStart = [ this ] ( ) {
2019-01-11 13:03:25 +01:00
curSession - > VerifyAndCommit ( pendingPrematureCommitments ) ;
2018-05-24 16:14:55 +02:00
} ;
auto fCommitWait = [ this ] {
2023-04-28 07:17:42 +02:00
return ProcessPendingMessageBatch < CDKGPrematureCommitment , MSG_QUORUM_PREMATURE_COMMITMENT > ( * curSession , * m_peerman , pendingPrematureCommitments , 8 ) ;
2018-05-24 16:14:55 +02:00
} ;
2022-03-13 21:56:31 +01:00
HandlePhase ( QuorumPhase : : Commit , QuorumPhase : : Finalize , curQuorumHash , 0.1 , fCommitStart , fCommitWait ) ;
2018-05-24 16:14:55 +02:00
auto finalCommitments = curSession - > FinalizeCommitments ( ) ;
2019-01-11 10:00:40 +01:00
for ( const auto & fqc : finalCommitments ) {
2022-09-22 13:14:48 +02:00
quorumBlockProcessor . AddMineableCommitment ( fqc ) ;
2018-05-24 16:14:55 +02:00
}
}
void CDKGSessionHandler : : PhaseHandlerThread ( )
{
2021-03-29 20:03:17 +02:00
while ( ! stopRequested ) {
2018-05-24 16:14:55 +02:00
try {
2022-06-27 12:02:46 +02:00
LogPrint ( BCLog : : LLMQ_DKG , " CDKGSessionHandler::%s -- %s qi[%d] - starting HandleDKGRound \n " , __func__ , params . name , quorumIndex ) ;
2018-05-24 16:14:55 +02:00
HandleDKGRound ( ) ;
} catch ( AbortPhaseException & e ) {
2022-09-22 13:14:48 +02:00
dkgDebugManager . UpdateLocalSessionStatus ( params . type , quorumIndex , [ & ] ( CDKGDebugSessionStatus & status ) {
2020-05-13 22:20:05 +02:00
status . statusBits . aborted = true ;
2019-01-08 09:55:19 +01:00
return true ;
} ) ;
2022-06-27 12:02:46 +02:00
LogPrint ( BCLog : : LLMQ_DKG , " CDKGSessionHandler::%s -- %s qi[%d] - aborted current DKG session \n " , __func__ , params . name , quorumIndex ) ;
2018-05-24 16:14:55 +02:00
}
}
}
2019-07-15 20:55:01 +02:00
} // namespace llmq