LCOV - code coverage report
Current view: top level - src/active - dkgsessionhandler.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 0 138 0.0 %
Date: 2026-06-25 07:23:51 Functions: 0 22 0.0 %

          Line data    Source code
       1             : // Copyright (c) 2018-2025 The Dash Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include <active/dkgsessionhandler.h>
       6             : 
       7             : #include <active/dkgsession.h>
       8             : #include <active/masternode.h>
       9             : #include <llmq/debug.h>
      10             : #include <llmq/dkgsession.h>
      11             : #include <llmq/net_quorum.h>
      12             : 
      13             : #include <chainparams.h>
      14             : #include <deploymentstatus.h>
      15             : #include <logging.h>
      16             : #include <util/time.h>
      17             : 
      18             : namespace llmq {
      19           0 : ActiveDKGSessionHandler::ActiveDKGSessionHandler(
      20             :     CBLSWorker& bls_worker, CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman,
      21             :     llmq::CDKGDebugManager& dkgdbgman, llmq::CDKGSessionManager& qdkgsman, llmq::CQuorumBlockProcessor& qblockman,
      22             :     llmq::CQuorumSnapshotManager& qsnapman, const CActiveMasternodeManager& mn_activeman, const ChainstateManager& chainman,
      23             :     const CSporkManager& sporkman, const Consensus::LLMQParams& llmq_params, bool quorums_watch, int quorums_idx) :
      24           0 :     llmq::CDKGSessionHandler(llmq_params),
      25           0 :     m_bls_worker{bls_worker},
      26           0 :     m_dmnman{dmnman},
      27           0 :     m_mn_metaman{mn_metaman},
      28           0 :     m_dkgdbgman{dkgdbgman},
      29           0 :     m_qdkgsman{qdkgsman},
      30           0 :     m_qblockman{qblockman},
      31           0 :     m_qsnapman{qsnapman},
      32           0 :     m_mn_activeman{mn_activeman},
      33           0 :     m_chainman{chainman},
      34           0 :     m_sporkman{sporkman},
      35           0 :     m_quorums_watch{quorums_watch},
      36           0 :     quorumIndex{quorums_idx}
      37           0 : {
      38           0 : }
      39             : 
      40           0 : ActiveDKGSessionHandler::~ActiveDKGSessionHandler() = default;
      41             : 
      42           0 : void ActiveDKGSessionHandler::UpdatedBlockTip(const CBlockIndex* pindexNew)
      43             : {
      44             :     //AssertLockNotHeld(cs_main);
      45             :     //Indexed quorums (greater than 0) are enabled with Quorum Rotation
      46           0 :     if (quorumIndex > 0 && !IsQuorumRotationEnabled(params, pindexNew)) {
      47           0 :         return;
      48             :     }
      49           0 :     LOCK(cs_phase_qhash);
      50             : 
      51           0 :     int quorumStageInt = (pindexNew->nHeight - quorumIndex) % params.dkgInterval;
      52             : 
      53           0 :     const CBlockIndex* pQuorumBaseBlockIndex = pindexNew->GetAncestor(pindexNew->nHeight - quorumStageInt);
      54             : 
      55           0 :     currentHeight = pindexNew->nHeight;
      56           0 :     quorumHash = pQuorumBaseBlockIndex->GetBlockHash();
      57             : 
      58           0 :     bool fNewPhase = (quorumStageInt % params.dkgPhaseBlocks) == 0;
      59           0 :     int phaseInt = quorumStageInt / params.dkgPhaseBlocks + 1;
      60           0 :     QuorumPhase oldPhase = phase;
      61           0 :     if (fNewPhase && phaseInt >= std23::to_underlying(QuorumPhase::Initialized) && phaseInt <= std23::to_underlying(QuorumPhase::Idle)) {
      62           0 :         phase = static_cast<QuorumPhase>(phaseInt);
      63           0 :     }
      64             : 
      65           0 :     LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] currentHeight=%d, pQuorumBaseBlockIndex->nHeight=%d, oldPhase=%d, newPhase=%d\n", __func__,
      66             :              params.name, quorumIndex, currentHeight, pQuorumBaseBlockIndex->nHeight, std23::to_underlying(oldPhase), std23::to_underlying(phase));
      67           0 : }
      68             : 
      69           0 : uint256 ActiveDKGSessionHandler::GetCurrentQuorumHash() const { return WITH_LOCK(cs_phase_qhash, return quorumHash); }
      70             : 
      71           0 : std::pair<QuorumPhase, uint256> ActiveDKGSessionHandler::GetPhaseAndQuorumHash() const
      72             : {
      73           0 :     LOCK(cs_phase_qhash);
      74           0 :     return std::make_pair(phase, quorumHash);
      75           0 : }
      76             : 
      77           0 : bool ActiveDKGSessionHandler::InitNewQuorum(gsl::not_null<const CBlockIndex*> pQuorumBaseBlockIndex)
      78             : {
      79           0 :     if (!DeploymentDIP0003Enforced(pQuorumBaseBlockIndex->nHeight, Params().GetConsensus())) {
      80           0 :         return false;
      81             :     }
      82             : 
      83           0 :     curSession = std::make_unique<ActiveDKGSession>(m_bls_worker, m_dmnman, m_dkgdbgman, m_qdkgsman, m_mn_metaman,
      84           0 :                                                     m_qsnapman, m_mn_activeman, m_chainman, m_sporkman,
      85           0 :                                                     pQuorumBaseBlockIndex, params);
      86             : 
      87           0 :     if (!curSession->Init(m_mn_activeman.GetProTxHash(), quorumIndex)) {
      88           0 :         LogPrintf("ActiveDKGSessionHandler::%s -- height[%d] quorum initialization failed for %s qi[%d]\n", __func__,
      89             :                   pQuorumBaseBlockIndex->nHeight, params.name, quorumIndex);
      90           0 :         return false;
      91             :     }
      92             : 
      93           0 :     LogPrintf("ActiveDKGSessionHandler::%s -- height[%d] quorum initialization OK for %s qi[%d]\n", __func__, pQuorumBaseBlockIndex->nHeight, params.name, quorumIndex);
      94           0 :     return true;
      95           0 : }
      96             : 
      97           0 : void ActiveDKGSessionHandler::WaitForNextPhase(std::optional<QuorumPhase> curPhase, QuorumPhase nextPhase,
      98             :                                                const uint256& expectedQuorumHash, const WhileWaitFunc& shouldNotWait) const
      99             : {
     100           0 :     LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - starting, curPhase=%d, nextPhase=%d\n", __func__, params.name, quorumIndex, curPhase.has_value() ? std23::to_underlying(*curPhase) : -1, std23::to_underlying(nextPhase));
     101             : 
     102           0 :     while (true) {
     103           0 :         if (stopRequested) {
     104           0 :             LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - aborting due to stop/shutdown requested\n", __func__, params.name, quorumIndex);
     105           0 :             throw AbortPhaseException();
     106             :         }
     107           0 :         auto [_phase, _quorumHash] = GetPhaseAndQuorumHash();
     108           0 :         if (!expectedQuorumHash.IsNull() && _quorumHash != expectedQuorumHash) {
     109           0 :             LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - aborting due unexpected expectedQuorumHash change\n", __func__, params.name, quorumIndex);
     110           0 :             throw AbortPhaseException();
     111             :         }
     112           0 :         if (_phase == nextPhase) {
     113           0 :             break;
     114             :         }
     115           0 :         if (curPhase.has_value() && _phase != curPhase) {
     116           0 :             LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - aborting due unexpected phase change, _phase=%d, curPhase=%d\n", __func__, params.name, quorumIndex, std23::to_underlying(_phase), curPhase.has_value() ? std23::to_underlying(*curPhase) : -1);
     117           0 :             throw AbortPhaseException();
     118             :         }
     119           0 :         if (!shouldNotWait()) {
     120           0 :             UninterruptibleSleep(std::chrono::milliseconds{100});
     121           0 :         }
     122             :     }
     123             : 
     124           0 :     LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - done, curPhase=%d, nextPhase=%d\n", __func__, params.name, quorumIndex, curPhase.has_value() ? std23::to_underlying(*curPhase) : -1, std23::to_underlying(nextPhase));
     125             : 
     126           0 :     if (nextPhase == QuorumPhase::Initialized) {
     127           0 :         m_dkgdbgman.ResetLocalSessionStatus(params.type, quorumIndex);
     128           0 :     } else {
     129           0 :         m_dkgdbgman.UpdateLocalSessionStatus(params.type, quorumIndex, [&](CDKGDebugSessionStatus& status) {
     130           0 :             bool changed = status.phase != nextPhase;
     131           0 :             status.phase = nextPhase;
     132           0 :             return changed;
     133             :         });
     134             :     }
     135           0 : }
     136             : 
     137           0 : void ActiveDKGSessionHandler::WaitForNewQuorum(const uint256& oldQuorumHash) const
     138             : {
     139           0 :     LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d]- starting\n", __func__, params.name, quorumIndex);
     140             : 
     141           0 :     while (true) {
     142           0 :         if (stopRequested) {
     143           0 :             LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - aborting due to stop/shutdown requested\n", __func__, params.name, quorumIndex);
     144           0 :             throw AbortPhaseException();
     145             :         }
     146           0 :         auto [_, _quorumHash] = GetPhaseAndQuorumHash();
     147           0 :         if (_quorumHash != oldQuorumHash) {
     148           0 :             break;
     149             :         }
     150           0 :         UninterruptibleSleep(std::chrono::milliseconds{100});
     151             :     }
     152             : 
     153           0 :     LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - done\n", __func__, params.name, quorumIndex);
     154           0 : }
     155             : 
     156             : // Sleep some time to not fully overload the whole network
     157           0 : void ActiveDKGSessionHandler::SleepBeforePhase(QuorumPhase curPhase, const uint256& expectedQuorumHash,
     158             :                                                double randomSleepFactor, const WhileWaitFunc& runWhileWaiting) const
     159             : {
     160           0 :     if (!curSession->AreWeMember()) {
     161             :         // Non-members do not participate and do not create any network load, no need to sleep.
     162           0 :         return;
     163             :     }
     164             : 
     165           0 :     if (Params().MineBlocksOnDemand()) {
     166             :         // On regtest, blocks can be mined on demand without any significant time passing between these.
     167             :         // We shouldn't wait before phases in this case.
     168           0 :         return;
     169             :     }
     170             : 
     171             :     // Two blocks can come very close to each other, this happens pretty regularly. We don't want to be
     172             :     // left behind and marked as a bad member. This means that we should not count the last block of the
     173             :     // phase as a safe one to keep sleeping, that's why we calculate the phase sleep time as a time of
     174             :     // the full phase minus one block here.
     175           0 :     double phaseSleepTime = (params.dkgPhaseBlocks - 1) * Params().GetConsensus().nPowTargetSpacing * 1000;
     176             :     // Expected phase sleep time per member
     177           0 :     double phaseSleepTimePerMember = phaseSleepTime / params.size;
     178             :     // Don't expect perfect block times and thus reduce the phase time to be on the secure side (caller chooses factor)
     179           0 :     double adjustedPhaseSleepTimePerMember = phaseSleepTimePerMember * randomSleepFactor;
     180             : 
     181           0 :     int64_t sleepTime = (int64_t)(adjustedPhaseSleepTimePerMember * curSession->GetMyMemberIndex().value_or(0));
     182           0 :     const auto endTime = SteadyClock::now() + std::chrono::milliseconds{sleepTime};
     183           0 :     int heightTmp{currentHeight.load()};
     184           0 :     int heightStart{heightTmp};
     185             : 
     186           0 :     LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - starting sleep for %d ms, curPhase=%d\n", __func__, params.name, quorumIndex, sleepTime, std23::to_underlying(curPhase));
     187             : 
     188           0 :     while (SteadyClock::now() < endTime) {
     189           0 :         if (stopRequested) {
     190           0 :             LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - aborting due to stop/shutdown requested\n", __func__, params.name, quorumIndex);
     191           0 :             throw AbortPhaseException();
     192             :         }
     193           0 :         auto cur_height = currentHeight.load();
     194           0 :         if (cur_height > heightTmp) {
     195             :             // New block(s) just came in
     196           0 :             int64_t expectedBlockTime = (cur_height - heightStart) * Params().GetConsensus().nPowTargetSpacing * 1000;
     197           0 :             if (expectedBlockTime > sleepTime) {
     198             :                 // Blocks came faster than we expected, jump into the phase func asap
     199           0 :                 break;
     200             :             }
     201           0 :             heightTmp = cur_height;
     202           0 :         }
     203           0 :         if (WITH_LOCK(cs_phase_qhash, return phase != curPhase || quorumHash != expectedQuorumHash)) {
     204             :             // Something went wrong and/or we missed quite a few blocks and it's just too late now
     205           0 :             LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - aborting due unexpected phase/expectedQuorumHash change\n", __func__, params.name, quorumIndex);
     206           0 :             throw AbortPhaseException();
     207             :         }
     208           0 :         if (!runWhileWaiting()) {
     209           0 :             UninterruptibleSleep(std::chrono::milliseconds{100});
     210           0 :         }
     211             :     }
     212             : 
     213           0 :     LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - done, curPhase=%d\n", __func__, params.name, quorumIndex, std23::to_underlying(curPhase));
     214           0 : }
     215             : 
     216           0 : void ActiveDKGSessionHandler::HandlePhase(QuorumPhase curPhase, QuorumPhase nextPhase,
     217             :                                           const uint256& expectedQuorumHash, double randomSleepFactor,
     218             :                                           const StartPhaseFunc& startPhaseFunc, const WhileWaitFunc& runWhileWaiting)
     219             : {
     220           0 :     LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - starting, curPhase=%d, nextPhase=%d\n", __func__, params.name, quorumIndex, std23::to_underlying(curPhase), std23::to_underlying(nextPhase));
     221             : 
     222           0 :     SleepBeforePhase(curPhase, expectedQuorumHash, randomSleepFactor, runWhileWaiting);
     223           0 :     startPhaseFunc();
     224           0 :     WaitForNextPhase(curPhase, nextPhase, expectedQuorumHash, runWhileWaiting);
     225             : 
     226           0 :     LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - done, curPhase=%d, nextPhase=%d\n", __func__, params.name, quorumIndex, std23::to_underlying(curPhase), std23::to_underlying(nextPhase));
     227           0 : }
     228             : 
     229           0 : bool ActiveDKGSessionHandler::GetContribution(const uint256& hash, CDKGContribution& ret) const
     230             : {
     231           0 :     return curSession && curSession->GetContribution(hash, ret);
     232             : }
     233             : 
     234           0 : bool ActiveDKGSessionHandler::GetComplaint(const uint256& hash, CDKGComplaint& ret) const
     235             : {
     236           0 :     return curSession && curSession->GetComplaint(hash, ret);
     237             : }
     238             : 
     239           0 : bool ActiveDKGSessionHandler::GetJustification(const uint256& hash, CDKGJustification& ret) const
     240             : {
     241           0 :     return curSession && curSession->GetJustification(hash, ret);
     242             : }
     243             : 
     244           0 : bool ActiveDKGSessionHandler::GetPrematureCommitment(const uint256& hash, CDKGPrematureCommitment& ret) const
     245             : {
     246           0 :     return curSession && curSession->GetPrematureCommitment(hash, ret);
     247             : }
     248             : 
     249           0 : QuorumPhase ActiveDKGSessionHandler::GetPhase() const
     250             : {
     251           0 :     return WITH_LOCK(cs_phase_qhash, return phase);
     252             : }
     253             : } // namespace llmq

Generated by: LCOV version 1.16