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