PIVX Core  5.6.99
P2P Digital Currency
pow.cpp
Go to the documentation of this file.
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 unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader* pblock)
20 {
21  const Consensus::Params& consensus = Params().GetConsensus();
22 
23  if (consensus.fPowNoRetargeting)
24  return pindexLast->nBits;
25 
26  /* current difficulty formula, pivx - DarkGravity v3, written by Evan Duffield - evan@dashpay.io */
27  const CBlockIndex* BlockLastSolved = pindexLast;
28  const CBlockIndex* BlockReading = pindexLast;
29  int64_t nActualTimespan = 0;
30  int64_t LastBlockTime = 0;
31  int64_t PastBlocksMin = 24;
32  int64_t PastBlocksMax = 24;
33  int64_t CountBlocks = 0;
34  arith_uint256 PastDifficultyAverage;
35  arith_uint256 PastDifficultyAveragePrev;
36  const arith_uint256& powLimit = UintToArith256(consensus.powLimit);
37 
38  if (BlockLastSolved == nullptr || BlockLastSolved->nHeight == 0 || BlockLastSolved->nHeight < PastBlocksMin) {
39  return powLimit.GetCompact();
40  }
41 
42  if (consensus.NetworkUpgradeActive(pindexLast->nHeight + 1, Consensus::UPGRADE_POS)) {
43  const bool fTimeV2 = !Params().IsRegTestNet() && consensus.IsTimeProtocolV2(pindexLast->nHeight+1);
44  const arith_uint256& bnTargetLimit = UintToArith256(consensus.ProofOfStakeLimit(fTimeV2));
45  const int64_t& nTargetTimespan = consensus.TargetTimespan(fTimeV2);
46 
47  int64_t nActualSpacing = 0;
48  if (pindexLast->nHeight != 0)
49  nActualSpacing = pindexLast->GetBlockTime() - pindexLast->pprev->GetBlockTime();
50  if (nActualSpacing < 0)
51  nActualSpacing = 1;
52  if (fTimeV2 && nActualSpacing > consensus.nTargetSpacing*10)
53  nActualSpacing = consensus.nTargetSpacing*10;
54 
55  // ppcoin: target change every block
56  // ppcoin: retarget with exponential moving toward target spacing
57  arith_uint256 bnNew;
58  bnNew.SetCompact(pindexLast->nBits);
59 
60  // on first block with V2 time protocol, reduce the difficulty by a factor 16
61  if (fTimeV2 && !consensus.IsTimeProtocolV2(pindexLast->nHeight))
62  bnNew <<= 4;
63 
64  int64_t nInterval = nTargetTimespan / consensus.nTargetSpacing;
65  bnNew *= ((nInterval - 1) * consensus.nTargetSpacing + nActualSpacing + nActualSpacing);
66  bnNew /= ((nInterval + 1) * consensus.nTargetSpacing);
67 
68  if (bnNew <= 0 || bnNew > bnTargetLimit)
69  bnNew = bnTargetLimit;
70 
71  return bnNew.GetCompact();
72  }
73 
74  for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) {
75  if (PastBlocksMax > 0 && i > PastBlocksMax) {
76  break;
77  }
78  CountBlocks++;
79 
80  if (CountBlocks <= PastBlocksMin) {
81  if (CountBlocks == 1) {
82  PastDifficultyAverage.SetCompact(BlockReading->nBits);
83  } else {
84  PastDifficultyAverage = ((PastDifficultyAveragePrev * CountBlocks) + (arith_uint256().SetCompact(BlockReading->nBits))) / (CountBlocks + 1);
85  }
86  PastDifficultyAveragePrev = PastDifficultyAverage;
87  }
88 
89  if (LastBlockTime > 0) {
90  int64_t Diff = (LastBlockTime - BlockReading->GetBlockTime());
91  nActualTimespan += Diff;
92  }
93  LastBlockTime = BlockReading->GetBlockTime();
94 
95  if (BlockReading->pprev == nullptr) {
96  assert(BlockReading);
97  break;
98  }
99  BlockReading = BlockReading->pprev;
100  }
101 
102  arith_uint256 bnNew(PastDifficultyAverage);
103 
104  int64_t _nTargetTimespan = CountBlocks * consensus.nTargetSpacing;
105 
106  if (nActualTimespan < _nTargetTimespan / 3)
107  nActualTimespan = _nTargetTimespan / 3;
108  if (nActualTimespan > _nTargetTimespan * 3)
109  nActualTimespan = _nTargetTimespan * 3;
110 
111  // Retarget
112  bnNew *= nActualTimespan;
113  bnNew /= _nTargetTimespan;
114 
115  if (bnNew > powLimit) {
116  bnNew = powLimit;
117  }
118 
119  return bnNew.GetCompact();
120 }
121 
122 bool CheckProofOfWork(uint256 hash, unsigned int nBits)
123 {
124  bool fNegative;
125  bool fOverflow;
126  arith_uint256 bnTarget;
127 
128  bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
129 
130  // Check range
131  if (fNegative || bnTarget.IsNull() || fOverflow || bnTarget > UintToArith256(Params().GetConsensus().powLimit))
132  return error("CheckProofOfWork() : nBits below minimum work");
133 
134  // Check proof of work matches claimed amount
135  if (UintToArith256(hash) > bnTarget)
136  return error("CheckProofOfWork() : hash doesn't match nBits");
137 
138  return true;
139 }
140 
142 {
143  arith_uint256 bnTarget;
144  bool fNegative;
145  bool fOverflow;
146  bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow);
147  if (fNegative || fOverflow || bnTarget.IsNull())
148  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  return (~bnTarget / (bnTarget + 1)) + 1;
154 }
arith_uint256 UintToArith256(const uint256 &a)
const arith_uint256 ARITH_UINT256_ZERO
const CChainParams & Params()
Return the currently selected parameters.
Nodes collect new transactions into a block, hash them into a hash tree, and scan through nonce value...
Definition: block.h:23
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:139
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition: chain.h:145
int64_t GetBlockTime() const
Definition: chain.h:216
uint32_t nBits
Definition: chain.h:197
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:151
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:72
bool IsRegTestNet() const
Definition: chainparams.h:98
256-bit unsigned big integer.
arith_uint256 & SetCompact(uint32_t nCompact, bool *pfNegative=nullptr, bool *pfOverflow=nullptr)
The "compact" format is a representation of a whole number N using an unsigned 32bit number similar t...
uint32_t GetCompact(bool fNegative=false) const
bool IsNull() const
256-bit opaque blob.
Definition: uint256.h:138
@ UPGRADE_POS
Definition: params.h:28
bool CheckProofOfWork(uint256 hash, unsigned int nBits)
Check whether a block hash satisfies the proof-of-work requirement specified by nBits.
Definition: pow.cpp:122
arith_uint256 GetBlockProof(const CBlockIndex &block)
Definition: pow.cpp:141
unsigned int GetNextWorkRequired(const CBlockIndex *pindexLast, const CBlockHeader *pblock)
Definition: pow.cpp:19
Parameters that influence chain consensus.
Definition: params.h:171
uint256 ProofOfStakeLimit(const bool fV2) const
Definition: params.h:216
bool IsTimeProtocolV2(const int nHeight) const
Definition: params.h:218
int64_t nTargetSpacing
Definition: params.h:193
bool fPowNoRetargeting
Definition: params.h:174
int64_t TargetTimespan(const bool fV2=true) const
Definition: params.h:215
uint256 powLimit
Definition: params.h:175
bool NetworkUpgradeActive(int nHeight, Consensus::UpgradeIndex idx) const
Returns true if the given network upgrade is active as of the given block height.
Definition: params.cpp:12
bool error(const char *fmt, const Args &... args)
Definition: system.h:77