LCOV - code coverage report
Current view: top level - src - pow.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 77 150 51.3 %
Date: 2026-06-25 07:23:51 Functions: 5 6 83.3 %

          Line data    Source code
       1             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2015 The Bitcoin Core developers
       3             : // Distributed under the MIT software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : #include <pow.h>
       7             : 
       8             : #include <arith_uint256.h>
       9             : #include <chain.h>
      10             : #include <primitives/block.h>
      11             : #include <uint256.h>
      12             : 
      13             : #include <math.h>
      14             : 
      15           0 : unsigned int static KimotoGravityWell(const CBlockIndex* pindexLast, const Consensus::Params& params) {
      16           0 :     const CBlockIndex *BlockLastSolved = pindexLast;
      17           0 :     const CBlockIndex *BlockReading = pindexLast;
      18           0 :     uint64_t PastBlocksMass = 0;
      19           0 :     int64_t PastRateActualSeconds = 0;
      20           0 :     int64_t PastRateTargetSeconds = 0;
      21           0 :     double PastRateAdjustmentRatio = double(1);
      22           0 :     arith_uint256 PastDifficultyAverage;
      23           0 :     arith_uint256 PastDifficultyAveragePrev;
      24             :     double EventHorizonDeviation;
      25             :     double EventHorizonDeviationFast;
      26             :     double EventHorizonDeviationSlow;
      27             : 
      28           0 :     uint64_t pastSecondsMin = params.nPowTargetTimespan * 0.025;
      29           0 :     uint64_t pastSecondsMax = params.nPowTargetTimespan * 7;
      30           0 :     uint64_t PastBlocksMin = pastSecondsMin / params.nPowTargetSpacing;
      31           0 :     uint64_t PastBlocksMax = pastSecondsMax / params.nPowTargetSpacing;
      32             : 
      33           0 :     if (BlockLastSolved == nullptr || BlockLastSolved->nHeight == 0 || (uint64_t)BlockLastSolved->nHeight < PastBlocksMin) { return UintToArith256(params.powLimit).GetCompact(); }
      34             : 
      35           0 :     for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) {
      36           0 :         if (PastBlocksMax > 0 && i > PastBlocksMax) { break; }
      37           0 :         PastBlocksMass++;
      38             : 
      39           0 :         PastDifficultyAverage.SetCompact(BlockReading->nBits);
      40           0 :         if (i > 1) {
      41             :             // handle negative arith_uint256
      42           0 :             if(PastDifficultyAverage >= PastDifficultyAveragePrev)
      43           0 :                 PastDifficultyAverage = ((PastDifficultyAverage - PastDifficultyAveragePrev) / i) + PastDifficultyAveragePrev;
      44             :             else
      45           0 :                 PastDifficultyAverage = PastDifficultyAveragePrev - ((PastDifficultyAveragePrev - PastDifficultyAverage) / i);
      46           0 :         }
      47           0 :         PastDifficultyAveragePrev = PastDifficultyAverage;
      48             : 
      49           0 :         PastRateActualSeconds = BlockLastSolved->GetBlockTime() - BlockReading->GetBlockTime();
      50           0 :         PastRateTargetSeconds = params.nPowTargetSpacing * PastBlocksMass;
      51           0 :         PastRateAdjustmentRatio = double(1);
      52           0 :         if (PastRateActualSeconds < 0) { PastRateActualSeconds = 0; }
      53           0 :         if (PastRateActualSeconds != 0 && PastRateTargetSeconds != 0) {
      54           0 :             PastRateAdjustmentRatio = double(PastRateTargetSeconds) / double(PastRateActualSeconds);
      55           0 :         }
      56           0 :         EventHorizonDeviation = 1 + (0.7084 * pow((double(PastBlocksMass)/double(28.2)), -1.228));
      57           0 :         EventHorizonDeviationFast = EventHorizonDeviation;
      58           0 :         EventHorizonDeviationSlow = 1 / EventHorizonDeviation;
      59             : 
      60           0 :         if (PastBlocksMass >= PastBlocksMin) {
      61           0 :                 if ((PastRateAdjustmentRatio <= EventHorizonDeviationSlow) || (PastRateAdjustmentRatio >= EventHorizonDeviationFast))
      62           0 :                 { assert(BlockReading); break; }
      63           0 :         }
      64           0 :         if (BlockReading->pprev == nullptr) { assert(BlockReading); break; }
      65           0 :         BlockReading = BlockReading->pprev;
      66           0 :     }
      67             : 
      68           0 :     arith_uint256 bnNew(PastDifficultyAverage);
      69           0 :     if (PastRateActualSeconds != 0 && PastRateTargetSeconds != 0) {
      70           0 :         bnNew *= PastRateActualSeconds;
      71           0 :         bnNew /= PastRateTargetSeconds;
      72           0 :     }
      73             : 
      74           0 :     if (bnNew > UintToArith256(params.powLimit)) {
      75           0 :         bnNew = UintToArith256(params.powLimit);
      76           0 :     }
      77             : 
      78           0 :     return bnNew.GetCompact();
      79           0 : }
      80             : 
      81           2 : unsigned int static DarkGravityWave(const CBlockIndex* pindexLast, const Consensus::Params& params) {
      82             :     /* current difficulty formula, dash - DarkGravity v3, written by Evan Duffield - evan@dash.org */
      83           2 :     const arith_uint256 bnPowLimit = UintToArith256(params.powLimit);
      84           2 :     int64_t nPastBlocks = 24;
      85             : 
      86             :     // make sure we have at least (nPastBlocks + 1) blocks, otherwise just return powLimit
      87           2 :     if (!pindexLast || pindexLast->nHeight < nPastBlocks) {
      88           0 :         return bnPowLimit.GetCompact();
      89             :     }
      90             : 
      91           2 :     const CBlockIndex *pindex = pindexLast;
      92           2 :     arith_uint256 bnPastTargetAvg;
      93             : 
      94          50 :     for (unsigned int nCountBlocks = 1; nCountBlocks <= nPastBlocks; nCountBlocks++) {
      95          48 :         arith_uint256 bnTarget = arith_uint256().SetCompact(pindex->nBits);
      96          48 :         if (nCountBlocks == 1) {
      97           2 :             bnPastTargetAvg = bnTarget;
      98           2 :         } else {
      99             :             // NOTE: that's not an average really...
     100          46 :             bnPastTargetAvg = (bnPastTargetAvg * nCountBlocks + bnTarget) / (nCountBlocks + 1);
     101             :         }
     102             : 
     103          48 :         if(nCountBlocks != nPastBlocks) {
     104          46 :             assert(pindex->pprev); // should never fail
     105          46 :             pindex = pindex->pprev;
     106          46 :         }
     107          48 :     }
     108             : 
     109           2 :     arith_uint256 bnNew(bnPastTargetAvg);
     110             : 
     111           2 :     int64_t nActualTimespan = pindexLast->GetBlockTime() - pindex->GetBlockTime();
     112             :     // NOTE: is this accurate? nActualTimespan counts it for (nPastBlocks - 1) blocks only...
     113           2 :     int64_t nTargetTimespan = nPastBlocks * params.nPowTargetSpacing;
     114             : 
     115           2 :     if (nActualTimespan < nTargetTimespan/3)
     116           0 :         nActualTimespan = nTargetTimespan/3;
     117           2 :     if (nActualTimespan > nTargetTimespan*3)
     118           0 :         nActualTimespan = nTargetTimespan*3;
     119             : 
     120             :     // Retarget
     121           2 :     bnNew *= nActualTimespan;
     122           2 :     bnNew /= nTargetTimespan;
     123             : 
     124           2 :     if (bnNew > bnPowLimit) {
     125           0 :         bnNew = bnPowLimit;
     126           0 :     }
     127             : 
     128           2 :     return bnNew.GetCompact();
     129           2 : }
     130             : 
     131       98066 : unsigned int GetNextWorkRequiredBTC(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
     132             : {
     133       98066 :     assert(pindexLast != nullptr);
     134       98066 :     unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact();
     135             : 
     136             :     // Only change once per interval
     137       98066 :     if ((pindexLast->nHeight+1) % params.DifficultyAdjustmentInterval() != 0)
     138             :     {
     139       97994 :         if (params.fPowAllowMinDifficultyBlocks)
     140             :         {
     141             :             // Special difficulty rule for testnet:
     142             :             // If the new block's timestamp is more than 2* 2.5 minutes
     143             :             // then allow mining of a min-difficulty block.
     144       97838 :             if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2)
     145        2688 :                 return nProofOfWorkLimit;
     146             :             else
     147             :             {
     148             :                 // Return the last non-special-min-difficulty-rules-block
     149       95150 :                 const CBlockIndex* pindex = pindexLast;
     150    20674696 :                 while (pindex->pprev && pindex->nHeight % params.DifficultyAdjustmentInterval() != 0 && pindex->nBits == nProofOfWorkLimit)
     151    20579546 :                     pindex = pindex->pprev;
     152       95150 :                 return pindex->nBits;
     153             :             }
     154             :         }
     155         156 :         return pindexLast->nBits;
     156             :     }
     157             : 
     158             :     // Go back by what we want to be 1 day worth of blocks
     159          72 :     int nHeightFirst = pindexLast->nHeight - (params.DifficultyAdjustmentInterval()-1);
     160          72 :     assert(nHeightFirst >= 0);
     161          72 :     const CBlockIndex* pindexFirst = pindexLast->GetAncestor(nHeightFirst);
     162          72 :     assert(pindexFirst);
     163             : 
     164          72 :    return CalculateNextWorkRequired(pindexLast, pindexFirst->GetBlockTime(), params);
     165       98066 : }
     166             : 
     167       98072 : unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
     168             : {
     169       98072 :     assert(pindexLast != nullptr);
     170       98072 :     assert(pblock != nullptr);
     171       98072 :     const arith_uint256 bnPowLimit = UintToArith256(params.powLimit);
     172             : 
     173             :     // this is only active on devnets
     174       98072 :     if (pindexLast->nHeight < params.nMinimumDifficultyBlocks) {
     175           0 :         return bnPowLimit.GetCompact();
     176             :     }
     177             : 
     178       98072 :     if (pindexLast->nHeight + 1 < params.nPowKGWHeight) {
     179       98066 :         return GetNextWorkRequiredBTC(pindexLast, pblock, params);
     180             :     }
     181             : 
     182             :     // Note: GetNextWorkRequiredBTC has it's own special difficulty rule,
     183             :     // so we only apply this to post-BTC algos.
     184           6 :     if (params.fPowNoRetargeting) {
     185           0 :         return bnPowLimit.GetCompact();
     186             :     }
     187             : 
     188           6 :     if (params.fPowAllowMinDifficultyBlocks) {
     189             :         // recent block is more than 2 hours old
     190           5 :         if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + 2 * 60 * 60) {
     191           2 :             return bnPowLimit.GetCompact();
     192             :         }
     193             :         // recent block is more than 10 minutes old
     194           3 :         if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing * 4) {
     195           2 :             arith_uint256 bnNew = arith_uint256().SetCompact(pindexLast->nBits) * 10;
     196           2 :             if (bnNew > bnPowLimit) {
     197           0 :                 return bnPowLimit.GetCompact();
     198             :             }
     199           2 :             return bnNew.GetCompact();
     200             :         }
     201           1 :     }
     202             : 
     203           2 :     if (pindexLast->nHeight + 1 < params.nPowDGWHeight) {
     204           0 :         return KimotoGravityWell(pindexLast, params);
     205             :     }
     206             : 
     207           2 :     return DarkGravityWave(pindexLast, params);
     208       98072 : }
     209             : 
     210             : // for DIFF_BTC only!
     211          72 : unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params)
     212             : {
     213          72 :     if (params.fPowNoRetargeting)
     214          72 :         return pindexLast->nBits;
     215             : 
     216             :     // Limit adjustment step
     217           0 :     int64_t nActualTimespan = pindexLast->GetBlockTime() - nFirstBlockTime;
     218           0 :     if (nActualTimespan < params.nPowTargetTimespan/4)
     219           0 :         nActualTimespan = params.nPowTargetTimespan/4;
     220           0 :     if (nActualTimespan > params.nPowTargetTimespan*4)
     221           0 :         nActualTimespan = params.nPowTargetTimespan*4;
     222             : 
     223             :     // Retarget
     224           0 :     const arith_uint256 bnPowLimit = UintToArith256(params.powLimit);
     225           0 :     arith_uint256 bnNew;
     226           0 :     bnNew.SetCompact(pindexLast->nBits);
     227           0 :     bnNew *= nActualTimespan;
     228           0 :     bnNew /= params.nPowTargetTimespan;
     229             : 
     230           0 :     if (bnNew > bnPowLimit)
     231           0 :         bnNew = bnPowLimit;
     232             : 
     233           0 :     return bnNew.GetCompact();
     234          72 : }
     235             : 
     236      726510 : bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params)
     237             : {
     238             :     bool fNegative;
     239             :     bool fOverflow;
     240      726510 :     arith_uint256 bnTarget;
     241             : 
     242      726510 :     bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
     243             : 
     244             :     // Check range
     245      726510 :     if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit))
     246           4 :         return false;
     247             : 
     248             :     // Check proof of work matches claimed amount
     249      726506 :     if (UintToArith256(hash) > bnTarget)
     250      607566 :         return false;
     251             : 
     252      118940 :     return true;
     253      726510 : }

Generated by: LCOV version 1.16