-
Notifications
You must be signed in to change notification settings - Fork 29
/
pow.cpp
132 lines (101 loc) · 4.45 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
// 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 "key.h"
#include "primitives/block.h"
#include "uint256.h"
#include <algorithm>
/* Locate a block meeting the range and type specified down the block index;
* for instance, range 1 PoW means to search for the nearest PoW block including
* the starting one, then find the previous PoW one and return its position */
const CBlockIndex *GetPrevBlockIndex(const CBlockIndex *pindex, unsigned int nRange, const bool fProofOfStake) {
nRange++;
while(nRange) {
if (pindex->IsProofOfStake() == fProofOfStake)
if (!(--nRange))
return pindex;
if (pindex->pprev)
pindex = pindex->pprev;
else
break;
}
return NULL;
}
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, bool fProofOfStake, const Consensus::Params& params)
{
arith_uint256 bnNew, bnTargetLimit;
bnTargetLimit.SetCompact(UintToArith256(params.powLimit).GetCompact());
/* The genesis block */
if (pindexLast == NULL)
return bnTargetLimit.GetCompact();
/* The latest block of the type requested */
const CBlockIndex *pindexPrev = GetPrevBlockIndex(pindexLast, 0, fProofOfStake);
if(pindexPrev == NULL)
return(bnTargetLimit.GetCompact());
if (params.fPowNoRetargeting)
return pindexLast->nBits;
/* Orbitcoin Super Shield (OSS);
* retargets every block using two averaging windows of 5 and 20 blocks,
* 0.25 damping and further oscillation limiting */
int64_t nIntervalShort = 5, nIntervalLong = 20, nTargetSpacing, nTargetTimespan,
nActualTimespan, nActualTimespanShort, nActualTimespanLong, nActualTimespanAvg,
nActualTimespanMax, nActualTimespanMin;
if (fProofOfStake)
nTargetSpacing = 6 * params.nBaseTargetSpacing;
else
nTargetSpacing = 3 * params.nBaseTargetSpacing;
nTargetTimespan = nTargetSpacing * nIntervalLong;
/* The short averaging window */
const CBlockIndex *pindexShort = GetPrevBlockIndex(pindexPrev, nIntervalShort, fProofOfStake);
if (!pindexShort)
return(bnTargetLimit.GetCompact());
nActualTimespanShort = (int64_t)pindexPrev->nTime - (int64_t)pindexShort->nTime;
/* The long averaging window */
const CBlockIndex *pindexLong = GetPrevBlockIndex(pindexShort, nIntervalLong - nIntervalShort, fProofOfStake);
if (!pindexLong)
return(bnTargetLimit.GetCompact());
nActualTimespanLong = (int64_t)pindexPrev->nTime - (int64_t)pindexLong->nTime;
/* Time warp protection */
nActualTimespanShort = std::max(nActualTimespanShort, (nTargetSpacing * nIntervalShort / 2));
nActualTimespanShort = std::min(nActualTimespanShort, (nTargetSpacing * nIntervalShort * 2));
nActualTimespanLong = std::max(nActualTimespanLong, (nTargetSpacing * nIntervalLong / 2));
nActualTimespanLong = std::min(nActualTimespanLong, (nTargetSpacing * nIntervalLong * 2));
/* The average of both windows */
nActualTimespanAvg = (nActualTimespanShort * (nIntervalLong / nIntervalShort) + nActualTimespanLong) / 2;
/* 0.25 damping */
nActualTimespan = nActualTimespanAvg + 3 * nTargetTimespan;
nActualTimespan /= 4;
/* Oscillation limiters */
/* +5% to -10% */
nActualTimespanMin = nTargetTimespan * 100 / 105;
nActualTimespanMax = nTargetTimespan * 110 / 100;
if (nActualTimespan < nActualTimespanMin)
nActualTimespan = nActualTimespanMin;
if (nActualTimespan > nActualTimespanMax)
nActualTimespan = nActualTimespanMax;
/* Retarget */
bnNew.SetCompact(pindexPrev->nBits);
bnNew *= nActualTimespan;
bnNew /= nTargetTimespan;
if (bnNew > bnTargetLimit)
bnNew = bnTargetLimit;
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;
}