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