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