LCOV - code coverage report
Current view: top level - src/chainlock - chainlock.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 37 95 38.9 %
Date: 2026-06-25 07:23:51 Functions: 14 20 70.0 %

          Line data    Source code
       1             : // Copyright (c) 2019-2026 The Dash Core developers
       2             : // Distributed under the MIT/X11 software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include <chainlock/chainlock.h>
       6             : 
       7             : #include <chain.h>
       8             : #include <logging.h>
       9             : #include <spork.h>
      10             : 
      11             : namespace chainlock {
      12             : 
      13       17810 : ChainLockSig::ChainLockSig() = default;
      14       63500 : ChainLockSig::~ChainLockSig() = default;
      15             : 
      16          24 : ChainLockSig::ChainLockSig(int32_t nHeight, const uint256& blockHash, const CBLSSignature& sig) :
      17          12 :     nHeight{nHeight},
      18          12 :     blockHash{blockHash},
      19          12 :     sig{sig}
      20          12 : {
      21          24 : }
      22             : 
      23           2 : std::string ChainLockSig::ToString() const
      24             : {
      25           2 :     return strprintf("ChainLockSig(nHeight=%d, blockHash=%s)", nHeight, blockHash.ToString());
      26           0 : }
      27             : 
      28        1881 : Chainlocks::Chainlocks(const CSporkManager& sporkman) :
      29         627 :     m_sporks(sporkman)
      30         627 : {
      31         627 : }
      32             : 
      33      145223 : bool Chainlocks::IsEnabled() const { return m_sporks.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED); }
      34             : 
      35           0 : bool Chainlocks::IsSigningEnabled() const { return m_sporks.GetSporkValue(SPORK_19_CHAINLOCKS_ENABLED) == 0; }
      36             : 
      37       22835 : chainlock::ChainLockSig Chainlocks::GetBestChainLock() const
      38             : {
      39       22835 :     LOCK(cs);
      40       22835 :     return bestChainLock;
      41       22835 : }
      42             : 
      43       49009 : int32_t Chainlocks::GetBestChainLockHeight() const
      44             : {
      45       49009 :     LOCK(cs);
      46       49009 :     return bestChainLock.getHeight();
      47       49009 : }
      48             : 
      49       47158 : bool Chainlocks::HasChainLock(int nHeight, const uint256& blockHash) const
      50             : {
      51       47158 :     LOCK(cs);
      52             : 
      53       47158 :     if (!IsEnabled()) {
      54       47157 :         return false;
      55             :     }
      56             : 
      57           1 :     if (bestChainLockBlockIndex == nullptr) {
      58           1 :         return false;
      59             :     }
      60             : 
      61           0 :     if (nHeight > bestChainLockBlockIndex->nHeight) {
      62           0 :         return false;
      63             :     }
      64             : 
      65           0 :     if (nHeight == bestChainLockBlockIndex->nHeight) {
      66           0 :         return blockHash == bestChainLockBlockIndex->GetBlockHash();
      67             :     }
      68             : 
      69           0 :     const auto* pAncestor = bestChainLockBlockIndex->GetAncestor(nHeight);
      70           0 :     return (pAncestor != nullptr) && pAncestor->GetBlockHash() == blockHash;
      71       47158 : }
      72             : 
      73       98065 : bool Chainlocks::HasConflictingChainLock(int nHeight, const uint256& blockHash) const
      74             : {
      75       98065 :     LOCK(cs);
      76             : 
      77       98065 :     if (!IsEnabled()) {
      78       97791 :         return false;
      79             :     }
      80             : 
      81         274 :     if (bestChainLockBlockIndex == nullptr) {
      82         274 :         return false;
      83             :     }
      84             : 
      85           0 :     if (nHeight > bestChainLockBlockIndex->nHeight) {
      86           0 :         return false;
      87             :     }
      88             : 
      89           0 :     if (nHeight == bestChainLockBlockIndex->nHeight) {
      90           0 :         return blockHash != bestChainLockBlockIndex->GetBlockHash();
      91             :     }
      92             : 
      93           0 :     const auto* pAncestor = bestChainLockBlockIndex->GetAncestor(nHeight);
      94           0 :     assert(pAncestor);
      95           0 :     return pAncestor->GetBlockHash() != blockHash;
      96       98065 : }
      97             : 
      98           0 : void Chainlocks::ResetChainlock()
      99             : {
     100           0 :     LOCK(cs);
     101           0 :     bestChainLockHash = uint256{};
     102           0 :     bestChainLock = bestChainLockWithKnownBlock = chainlock::ChainLockSig{};
     103           0 :     bestChainLockBlockIndex = nullptr;
     104           0 : }
     105             : 
     106           0 : bool Chainlocks::UpdateBestChainlock(const uint256& hash, const chainlock::ChainLockSig& clsig, const CBlockIndex* pindex)
     107             : {
     108           0 :     LOCK(cs);
     109             : 
     110           0 :     if (clsig.getHeight() <= bestChainLock.getHeight()) {
     111             :         // no need to process older/same CLSIGs
     112           0 :         return false;
     113             :     }
     114             : 
     115           0 :     bestChainLockHash = hash;
     116           0 :     bestChainLock = clsig;
     117             : 
     118           0 :     if (pindex) {
     119           0 :         if (pindex->nHeight != clsig.getHeight()) {
     120             :             // Should not happen, same as the conflict check from above.
     121           0 :             LogPrintf("Chainlocks::%s -- height of CLSIG (%s) does not match the specified block's height (%d)\n",
     122             :                       __func__, clsig.ToString(), pindex->nHeight);
     123             :             // Note: not relaying clsig here
     124           0 :             return false;
     125             :         }
     126           0 :         bestChainLockWithKnownBlock = clsig;
     127           0 :         bestChainLockBlockIndex = pindex;
     128           0 :     }
     129             :     // We don't know the block/header for this CLSIG yet, so bail out for now and when the
     130             :     // block/header later comes in, we will enforce the correct chain. We still relay further.
     131           0 :     return true;
     132           0 : }
     133             : 
     134           0 : std::pair<chainlock::ChainLockSig, const CBlockIndex*> Chainlocks::GetBestChainlockWithPindex() const
     135             : {
     136           0 :     LOCK(cs);
     137           0 :     return {bestChainLockWithKnownBlock, bestChainLockBlockIndex};
     138           0 : }
     139             : 
     140           0 : bool Chainlocks::GetChainLockByHash(const uint256& hash, chainlock::ChainLockSig& ret) const
     141             : {
     142           0 :     LOCK(cs);
     143             : 
     144           0 :     if (bestChainLockHash != hash) {
     145             :         // we only propagate the best one and ditch all the old ones
     146           0 :         return false;
     147             :     }
     148           0 :     ret = bestChainLock;
     149           0 :     return true;
     150           0 : }
     151             : 
     152           0 : void Chainlocks::AcceptedBlockHeader(gsl::not_null<const CBlockIndex*> pindexNew)
     153             : {
     154           0 :     LOCK(cs);
     155             : 
     156           0 :     if (pindexNew->GetBlockHash() == bestChainLock.getBlockHash()) {
     157           0 :         LogPrint(BCLog::CHAINLOCKS, "Chainlocks::%s -- block header %s came in late, updating and enforcing\n",
     158             :                  __func__, pindexNew->GetBlockHash().ToString());
     159             : 
     160           0 :         if (bestChainLock.getHeight() != pindexNew->nHeight) {
     161             :             // Should not happen, same as the conflict check from ProcessNewChainLock.
     162           0 :             LogPrintf("Chainlocks::%s -- height of CLSIG (%s) does not match the specified block's height (%d)\n",
     163             :                       __func__, bestChainLock.ToString(), pindexNew->nHeight);
     164           0 :             return;
     165             :         }
     166             : 
     167             :         // when EnforceBestChainLock is called later, it might end up invalidating other chains but not activating the
     168             :         // CLSIG locked chain. This happens when only the header is known but the block is still missing yet. The usual
     169             :         // block processing logic will handle this when the block arrives
     170           0 :         bestChainLockWithKnownBlock = bestChainLock;
     171           0 :         bestChainLockBlockIndex = pindexNew;
     172           0 :     }
     173           0 : }
     174             : } // namespace chainlock

Generated by: LCOV version 1.16