LCOV - code coverage report
Current view: top level - src/chainlock - chainlock.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 90 95 94.7 %
Date: 2026-06-25 07:23:43 Functions: 20 20 100.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      145404 : ChainLockSig::ChainLockSig() = default;
      14      632522 : ChainLockSig::~ChainLockSig() = default;
      15             : 
      16       19298 : ChainLockSig::ChainLockSig(int32_t nHeight, const uint256& blockHash, const CBLSSignature& sig) :
      17        9649 :     nHeight{nHeight},
      18        9649 :     blockHash{blockHash},
      19        9649 :     sig{sig}
      20        9649 : {
      21       19298 : }
      22             : 
      23       86172 : std::string ChainLockSig::ToString() const
      24             : {
      25       86172 :     return strprintf("ChainLockSig(nHeight=%d, blockHash=%s)", nHeight, blockHash.ToString());
      26           0 : }
      27             : 
      28       10686 : Chainlocks::Chainlocks(const CSporkManager& sporkman) :
      29        3562 :     m_sporks(sporkman)
      30        3562 : {
      31        3562 : }
      32             : 
      33     1984847 : bool Chainlocks::IsEnabled() const { return m_sporks.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED); }
      34             : 
      35       67881 : bool Chainlocks::IsSigningEnabled() const { return m_sporks.GetSporkValue(SPORK_19_CHAINLOCKS_ENABLED) == 0; }
      36             : 
      37      135543 : chainlock::ChainLockSig Chainlocks::GetBestChainLock() const
      38             : {
      39      135543 :     LOCK(cs);
      40      135543 :     return bestChainLock;
      41      135543 : }
      42             : 
      43      445708 : int32_t Chainlocks::GetBestChainLockHeight() const
      44             : {
      45      445708 :     LOCK(cs);
      46      445708 :     return bestChainLock.getHeight();
      47      445708 : }
      48             : 
      49      643813 : bool Chainlocks::HasChainLock(int nHeight, const uint256& blockHash) const
      50             : {
      51      643813 :     LOCK(cs);
      52             : 
      53      643813 :     if (!IsEnabled()) {
      54      260530 :         return false;
      55             :     }
      56             : 
      57      383283 :     if (bestChainLockBlockIndex == nullptr) {
      58      135372 :         return false;
      59             :     }
      60             : 
      61      247911 :     if (nHeight > bestChainLockBlockIndex->nHeight) {
      62      182087 :         return false;
      63             :     }
      64             : 
      65       65824 :     if (nHeight == bestChainLockBlockIndex->nHeight) {
      66       21580 :         return blockHash == bestChainLockBlockIndex->GetBlockHash();
      67             :     }
      68             : 
      69       44244 :     const auto* pAncestor = bestChainLockBlockIndex->GetAncestor(nHeight);
      70       88488 :     return (pAncestor != nullptr) && pAncestor->GetBlockHash() == blockHash;
      71      643813 : }
      72             : 
      73      759058 : bool Chainlocks::HasConflictingChainLock(int nHeight, const uint256& blockHash) const
      74             : {
      75      759058 :     LOCK(cs);
      76             : 
      77      759058 :     if (!IsEnabled()) {
      78      534608 :         return false;
      79             :     }
      80             : 
      81      224450 :     if (bestChainLockBlockIndex == nullptr) {
      82       96435 :         return false;
      83             :     }
      84             : 
      85      128015 :     if (nHeight > bestChainLockBlockIndex->nHeight) {
      86      127913 :         return false;
      87             :     }
      88             : 
      89         102 :     if (nHeight == bestChainLockBlockIndex->nHeight) {
      90          64 :         return blockHash != bestChainLockBlockIndex->GetBlockHash();
      91             :     }
      92             : 
      93          38 :     const auto* pAncestor = bestChainLockBlockIndex->GetAncestor(nHeight);
      94          38 :     assert(pAncestor);
      95          38 :     return pAncestor->GetBlockHash() != blockHash;
      96      759058 : }
      97             : 
      98         688 : void Chainlocks::ResetChainlock()
      99             : {
     100         688 :     LOCK(cs);
     101         688 :     bestChainLockHash = uint256{};
     102         688 :     bestChainLock = bestChainLockWithKnownBlock = chainlock::ChainLockSig{};
     103         688 :     bestChainLockBlockIndex = nullptr;
     104         688 : }
     105             : 
     106       13550 : bool Chainlocks::UpdateBestChainlock(const uint256& hash, const chainlock::ChainLockSig& clsig, const CBlockIndex* pindex)
     107             : {
     108       13550 :     LOCK(cs);
     109             : 
     110       13550 :     if (clsig.getHeight() <= bestChainLock.getHeight()) {
     111             :         // no need to process older/same CLSIGs
     112           1 :         return false;
     113             :     }
     114             : 
     115       13549 :     bestChainLockHash = hash;
     116       13549 :     bestChainLock = clsig;
     117             : 
     118       13549 :     if (pindex) {
     119       13536 :         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       13536 :         bestChainLockWithKnownBlock = clsig;
     127       13536 :         bestChainLockBlockIndex = pindex;
     128       13536 :     }
     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       13549 :     return true;
     132       13550 : }
     133             : 
     134       84820 : std::pair<chainlock::ChainLockSig, const CBlockIndex*> Chainlocks::GetBestChainlockWithPindex() const
     135             : {
     136       84820 :     LOCK(cs);
     137       84820 :     return {bestChainLockWithKnownBlock, bestChainLockBlockIndex};
     138       84820 : }
     139             : 
     140        9570 : bool Chainlocks::GetChainLockByHash(const uint256& hash, chainlock::ChainLockSig& ret) const
     141             : {
     142        9570 :     LOCK(cs);
     143             : 
     144        9570 :     if (bestChainLockHash != hash) {
     145             :         // we only propagate the best one and ditch all the old ones
     146         134 :         return false;
     147             :     }
     148        9436 :     ret = bestChainLock;
     149        9436 :     return true;
     150        9570 : }
     151             : 
     152      244470 : void Chainlocks::AcceptedBlockHeader(gsl::not_null<const CBlockIndex*> pindexNew)
     153             : {
     154      244470 :     LOCK(cs);
     155             : 
     156      244470 :     if (pindexNew->GetBlockHash() == bestChainLock.getBlockHash()) {
     157          13 :         LogPrint(BCLog::CHAINLOCKS, "Chainlocks::%s -- block header %s came in late, updating and enforcing\n",
     158             :                  __func__, pindexNew->GetBlockHash().ToString());
     159             : 
     160          13 :         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          13 :         bestChainLockWithKnownBlock = bestChainLock;
     171          13 :         bestChainLockBlockIndex = pindexNew;
     172          13 :     }
     173      244470 : }
     174             : } // namespace chainlock

Generated by: LCOV version 1.16