Line data Source code
1 : // Copyright (c) 2009-2010 Satoshi Nakamoto 2 : // Copyright (c) 2009-2014 The Bitcoin developers 3 : // Copyright (c) 2014-2015 The Dash developers 4 : // Copyright (c) 2015-2021 The PIVX Core developers 5 : // Distributed under the MIT/X11 software license, see the accompanying 6 : // file COPYING or http://www.opensource.org/licenses/mit-license.php. 7 : 8 : #include "pow.h" 9 : 10 : #include "chain.h" 11 : #include "chainparams.h" 12 : #include "primitives/block.h" 13 : #include "uint256.h" 14 : #include "util/system.h" 15 : 16 : #include <math.h> 17 : 18 : 19 71945 : unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader* pblock) 20 : { 21 71945 : const Consensus::Params& consensus = Params().GetConsensus(); 22 : 23 71945 : if (consensus.fPowNoRetargeting) 24 71945 : return pindexLast->nBits; 25 : 26 : /* current difficulty formula, pivx - DarkGravity v3, written by Evan Duffield - evan@dashpay.io */ 27 0 : const CBlockIndex* BlockLastSolved = pindexLast; 28 0 : const CBlockIndex* BlockReading = pindexLast; 29 0 : int64_t nActualTimespan = 0; 30 0 : int64_t LastBlockTime = 0; 31 0 : int64_t PastBlocksMin = 24; 32 0 : int64_t PastBlocksMax = 24; 33 0 : int64_t CountBlocks = 0; 34 0 : arith_uint256 PastDifficultyAverage; 35 0 : arith_uint256 PastDifficultyAveragePrev; 36 0 : const arith_uint256& powLimit = UintToArith256(consensus.powLimit); 37 : 38 0 : if (BlockLastSolved == nullptr || BlockLastSolved->nHeight == 0 || BlockLastSolved->nHeight < PastBlocksMin) { 39 0 : return powLimit.GetCompact(); 40 : } 41 : 42 0 : if (consensus.NetworkUpgradeActive(pindexLast->nHeight + 1, Consensus::UPGRADE_POS)) { 43 0 : const bool fTimeV2 = !Params().IsRegTestNet() && consensus.IsTimeProtocolV2(pindexLast->nHeight+1); 44 0 : const arith_uint256& bnTargetLimit = UintToArith256(consensus.ProofOfStakeLimit(fTimeV2)); 45 0 : const int64_t& nTargetTimespan = consensus.TargetTimespan(fTimeV2); 46 : 47 0 : int64_t nActualSpacing = 0; 48 0 : if (pindexLast->nHeight != 0) 49 0 : nActualSpacing = pindexLast->GetBlockTime() - pindexLast->pprev->GetBlockTime(); 50 0 : if (nActualSpacing < 0) 51 0 : nActualSpacing = 1; 52 0 : if (fTimeV2 && nActualSpacing > consensus.nTargetSpacing*10) 53 0 : nActualSpacing = consensus.nTargetSpacing*10; 54 : 55 : // ppcoin: target change every block 56 : // ppcoin: retarget with exponential moving toward target spacing 57 0 : arith_uint256 bnNew; 58 0 : bnNew.SetCompact(pindexLast->nBits); 59 : 60 : // on first block with V2 time protocol, reduce the difficulty by a factor 16 61 0 : if (fTimeV2 && !consensus.IsTimeProtocolV2(pindexLast->nHeight)) 62 0 : bnNew <<= 4; 63 : 64 0 : int64_t nInterval = nTargetTimespan / consensus.nTargetSpacing; 65 0 : bnNew *= ((nInterval - 1) * consensus.nTargetSpacing + nActualSpacing + nActualSpacing); 66 0 : bnNew /= ((nInterval + 1) * consensus.nTargetSpacing); 67 : 68 0 : if (bnNew <= 0 || bnNew > bnTargetLimit) 69 0 : bnNew = bnTargetLimit; 70 : 71 0 : return bnNew.GetCompact(); 72 : } 73 : 74 0 : for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) { 75 0 : if (PastBlocksMax > 0 && i > PastBlocksMax) { 76 : break; 77 : } 78 0 : CountBlocks++; 79 : 80 0 : if (CountBlocks <= PastBlocksMin) { 81 0 : if (CountBlocks == 1) { 82 0 : PastDifficultyAverage.SetCompact(BlockReading->nBits); 83 : } else { 84 0 : PastDifficultyAverage = ((PastDifficultyAveragePrev * CountBlocks) + (arith_uint256().SetCompact(BlockReading->nBits))) / (CountBlocks + 1); 85 : } 86 0 : PastDifficultyAveragePrev = PastDifficultyAverage; 87 : } 88 : 89 0 : if (LastBlockTime > 0) { 90 0 : int64_t Diff = (LastBlockTime - BlockReading->GetBlockTime()); 91 0 : nActualTimespan += Diff; 92 : } 93 0 : LastBlockTime = BlockReading->GetBlockTime(); 94 : 95 0 : if (BlockReading->pprev == nullptr) { 96 : assert(BlockReading); 97 : break; 98 : } 99 0 : BlockReading = BlockReading->pprev; 100 : } 101 : 102 0 : arith_uint256 bnNew(PastDifficultyAverage); 103 : 104 0 : int64_t _nTargetTimespan = CountBlocks * consensus.nTargetSpacing; 105 : 106 0 : if (nActualTimespan < _nTargetTimespan / 3) 107 0 : nActualTimespan = _nTargetTimespan / 3; 108 0 : if (nActualTimespan > _nTargetTimespan * 3) 109 0 : nActualTimespan = _nTargetTimespan * 3; 110 : 111 : // Retarget 112 0 : bnNew *= nActualTimespan; 113 0 : bnNew /= _nTargetTimespan; 114 : 115 0 : if (bnNew > powLimit) { 116 0 : bnNew = powLimit; 117 : } 118 : 119 0 : return bnNew.GetCompact(); 120 : } 121 : 122 179272 : bool CheckProofOfWork(uint256 hash, unsigned int nBits) 123 : { 124 179272 : bool fNegative; 125 179272 : bool fOverflow; 126 179272 : arith_uint256 bnTarget; 127 : 128 179272 : bnTarget.SetCompact(nBits, &fNegative, &fOverflow); 129 : 130 : // Check range 131 537816 : if (fNegative || bnTarget.IsNull() || fOverflow || bnTarget > UintToArith256(Params().GetConsensus().powLimit)) 132 0 : return error("CheckProofOfWork() : nBits below minimum work"); 133 : 134 : // Check proof of work matches claimed amount 135 358544 : if (UintToArith256(hash) > bnTarget) 136 13295 : return error("CheckProofOfWork() : hash doesn't match nBits"); 137 : 138 : return true; 139 : } 140 : 141 74923 : arith_uint256 GetBlockProof(const CBlockIndex& block) 142 : { 143 74923 : arith_uint256 bnTarget; 144 74923 : bool fNegative; 145 74923 : bool fOverflow; 146 74923 : bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); 147 149846 : if (fNegative || fOverflow || bnTarget.IsNull()) 148 0 : return ARITH_UINT256_ZERO; 149 : // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256 150 : // as it's too large for a uint256. However, as 2**256 is at least as large 151 : // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1, 152 : // or ~bnTarget / (nTarget+1) + 1. 153 1123845 : return (~bnTarget / (bnTarget + 1)) + 1; 154 : }