pow.cpp raw
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2022 The Limenka 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 <pow_fork.h>
11 #include <primitives/block.h>
12 #include <uint256.h>
13 #include <util/check.h>
14
15 unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
16 {
17 assert(pindexLast != nullptr);
18
19 // Mine-on-demand (test mode): fixed powLimit, no retargeting, no
20 // fork DAA. Used by -forkmineondemand for the functional test and
21 // testnet bootstrap.
22 if (params.fPowNoRetargeting) {
23 return UintToArith256(params.powLimit).GetCompact();
24 }
25
26 // Fork chain: single-lane PI difficulty targeting.
27 if (IsForkActive(pindexLast, params)) {
28 return CalculateForkTarget(pindexLast, pblock, params);
29 }
30
31 unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact();
32
33 // Only change once per difficulty adjustment interval
34 if ((pindexLast->nHeight+1) % params.DifficultyAdjustmentInterval() != 0)
35 {
36 if (params.fPowAllowMinDifficultyBlocks)
37 {
38 // Special difficulty rule for testnet:
39 // If the new block's timestamp is more than 2* 10 minutes
40 // then allow mining of a min-difficulty block.
41 if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2)
42 return nProofOfWorkLimit;
43 else
44 {
45 // Return the last non-special-min-difficulty-rules-block
46 const CBlockIndex* pindex = pindexLast;
47 while (pindex->pprev && pindex->nHeight % params.DifficultyAdjustmentInterval() != 0 && pindex->nBits == nProofOfWorkLimit)
48 pindex = pindex->pprev;
49 return pindex->nBits;
50 }
51 }
52 return pindexLast->nBits;
53 }
54
55 // Go back by what we want to be 14 days worth of blocks
56 int nHeightFirst = pindexLast->nHeight - (params.DifficultyAdjustmentInterval()-1);
57 assert(nHeightFirst >= 0);
58 const CBlockIndex* pindexFirst = pindexLast->GetAncestor(nHeightFirst);
59 assert(pindexFirst);
60
61 return CalculateNextWorkRequired(pindexLast, pindexFirst->GetBlockTime(), params);
62 }
63
64 unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params)
65 {
66 if (params.fPowNoRetargeting)
67 return pindexLast->nBits;
68
69 // Limit adjustment step
70 int64_t nActualTimespan = pindexLast->GetBlockTime() - nFirstBlockTime;
71 if (nActualTimespan < params.nPowTargetTimespan/4)
72 nActualTimespan = params.nPowTargetTimespan/4;
73 if (nActualTimespan > params.nPowTargetTimespan*4)
74 nActualTimespan = params.nPowTargetTimespan*4;
75
76 // Retarget
77 const arith_uint256 bnPowLimit = UintToArith256(params.powLimit);
78 arith_uint256 bnNew;
79
80 // Special difficulty rule for Testnet4
81 if (params.enforce_BIP94) {
82 // Here we use the first block of the difficulty period. This way
83 // the real difficulty is always preserved in the first block as
84 // it is not allowed to use the min-difficulty exception.
85 int nHeightFirst = pindexLast->nHeight - (params.DifficultyAdjustmentInterval()-1);
86 const CBlockIndex* pindexFirst = pindexLast->GetAncestor(nHeightFirst);
87 bnNew.SetCompact(pindexFirst->nBits);
88 } else {
89 bnNew.SetCompact(pindexLast->nBits);
90 }
91
92 bnNew *= nActualTimespan;
93 bnNew /= params.nPowTargetTimespan;
94
95 if (bnNew > bnPowLimit)
96 bnNew = bnPowLimit;
97
98 return bnNew.GetCompact();
99 }
100
101 // Check that on difficulty adjustments, the new difficulty does not increase
102 // or decrease beyond the permitted limits.
103 bool PermittedDifficultyTransition(const Consensus::Params& params, int64_t height, uint32_t old_nbits, uint32_t new_nbits)
104 {
105 if (params.fPowAllowMinDifficultyBlocks) return true;
106
107 if (height % params.DifficultyAdjustmentInterval() == 0) {
108 int64_t smallest_timespan = params.nPowTargetTimespan/4;
109 int64_t largest_timespan = params.nPowTargetTimespan*4;
110
111 const arith_uint256 pow_limit = UintToArith256(params.powLimit);
112 arith_uint256 observed_new_target;
113 observed_new_target.SetCompact(new_nbits);
114
115 // Calculate the largest difficulty value possible:
116 arith_uint256 largest_difficulty_target;
117 largest_difficulty_target.SetCompact(old_nbits);
118 largest_difficulty_target *= largest_timespan;
119 largest_difficulty_target /= params.nPowTargetTimespan;
120
121 if (largest_difficulty_target > pow_limit) {
122 largest_difficulty_target = pow_limit;
123 }
124
125 // Round and then compare this new calculated value to what is
126 // observed.
127 arith_uint256 maximum_new_target;
128 maximum_new_target.SetCompact(largest_difficulty_target.GetCompact());
129 if (maximum_new_target < observed_new_target) return false;
130
131 // Calculate the smallest difficulty value possible:
132 arith_uint256 smallest_difficulty_target;
133 smallest_difficulty_target.SetCompact(old_nbits);
134 smallest_difficulty_target *= smallest_timespan;
135 smallest_difficulty_target /= params.nPowTargetTimespan;
136
137 if (smallest_difficulty_target > pow_limit) {
138 smallest_difficulty_target = pow_limit;
139 }
140
141 // Round and then compare this new calculated value to what is
142 // observed.
143 arith_uint256 minimum_new_target;
144 minimum_new_target.SetCompact(smallest_difficulty_target.GetCompact());
145 if (minimum_new_target > observed_new_target) return false;
146 } else if (old_nbits != new_nbits) {
147 return false;
148 }
149 return true;
150 }
151
152 // Bypasses the actual proof of work check during fuzz testing with a simplified validation checking whether
153 // the most significant bit of the last byte of the hash is set.
154 bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params)
155 {
156 if constexpr (G_FUZZING) return (hash.data()[31] & 0x80) == 0;
157 auto bnTarget{DeriveTarget(nBits, params.powLimit)};
158 if (!bnTarget) return false;
159
160 // Check proof of work matches claimed amount
161 if (UintToArith256(hash) > bnTarget)
162 return false;
163
164 return true;
165 }
166
167 std::optional<arith_uint256> DeriveTarget(unsigned int nBits, const uint256 pow_limit)
168 {
169 bool fNegative;
170 bool fOverflow;
171 arith_uint256 bnTarget;
172
173 bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
174
175 // Check range
176 if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(pow_limit))
177 return {};
178
179 return bnTarget;
180 }
181