Skip to content

Commit be51cf2

Browse files
committed
Implement simple moving average over work difficulty adjustement algorithm.
Summary: As per title. Hopefully this is much simpler than alternative, but more complex alternative do not perform suffisciently better to be worth it. Test Plan: make check Added unit tests for it. Reviewers: kyuupichan, Mengerian, #bitcoin_abc, schancel Reviewed By: Mengerian, #bitcoin_abc, schancel Subscribers: zanza321 Differential Revision: https://reviews.bitcoinabc.org/D601
1 parent a438bb8 commit be51cf2

5 files changed

Lines changed: 317 additions & 4 deletions

File tree

src/chain.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,9 +353,12 @@ class CBlockIndex {
353353
};
354354

355355
arith_uint256 GetBlockProof(const CBlockIndex &block);
356-
/** Return the time it would take to redo the work difference between from and
356+
357+
/**
358+
* Return the time it would take to redo the work difference between from and
357359
* to, assuming the current hashrate corresponds to the difficulty at tip, in
358-
* seconds. */
360+
* seconds.
361+
*/
359362
int64_t GetBlockProofEquivalentTime(const CBlockIndex &to,
360363
const CBlockIndex &from,
361364
const CBlockIndex &tip,

src/consensus/params.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#define BITCOIN_CONSENSUS_PARAMS_H
88

99
#include "uint256.h"
10+
1011
#include <map>
1112
#include <string>
1213

src/pow.cpp

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Copyright (c) 2009-2010 Satoshi Nakamoto
22
// Copyright (c) 2009-2016 The Bitcoin Core developers
3+
// Copyright (c) 2017 The Bitcoin developers
34
// Distributed under the MIT software license, see the accompanying
45
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
56

@@ -149,3 +150,124 @@ bool CheckProofOfWork(uint256 hash, uint32_t nBits,
149150

150151
return true;
151152
}
153+
154+
/**
155+
* Compute the a target based on the work done between 2 blocks and the time
156+
* required to produce that work.
157+
*/
158+
static arith_uint256 ComputeTarget(const CBlockIndex *pindexFirst,
159+
const CBlockIndex *pindexLast,
160+
const Consensus::Params &params) {
161+
assert(pindexLast->nHeight > pindexFirst->nHeight);
162+
163+
/**
164+
* From the total work done and the time it took to produce that much work,
165+
* we can deduce how much work we expect to be produced in the targeted time
166+
* between blocks.
167+
*/
168+
arith_uint256 work = pindexLast->nChainWork - pindexFirst->nChainWork;
169+
work *= params.nPowTargetSpacing;
170+
171+
// In order to avoid difficulty cliffs, we bound the amplitude of the
172+
// adjustement we are going to do.
173+
assert(pindexLast->nTime > pindexFirst->nTime);
174+
int64_t nActualTimespan = pindexLast->nTime - pindexFirst->nTime;
175+
if (nActualTimespan > 288 * params.nPowTargetSpacing) {
176+
nActualTimespan = 288 * params.nPowTargetSpacing;
177+
} else if (nActualTimespan < 72 * params.nPowTargetSpacing) {
178+
nActualTimespan = 72 * params.nPowTargetSpacing;
179+
}
180+
181+
work /= nActualTimespan;
182+
183+
/**
184+
* We need to compute T = (2^256 / W) - 1 but 2^256 doesn't fit in 256 bits.
185+
* By expressing 1 as W / W, we get (2^256 - W) / W, and we can compute
186+
* 2^256 - W as the complement of W.
187+
*/
188+
return (-work) / work;
189+
}
190+
191+
/**
192+
* To reduce the impact of timestamp manipulation, we select the block we are
193+
* basing our computation on via a median of 3.
194+
*/
195+
static const CBlockIndex *GetSuitableBlock(const CBlockIndex *pindex) {
196+
assert(pindex->nHeight >= 3);
197+
198+
/**
199+
* In order to avoid a block is a very skewed timestamp to have too much
200+
* influence, we select the median of the 3 top most blocks as a starting
201+
* point.
202+
*/
203+
const CBlockIndex *blocks[3];
204+
blocks[2] = pindex;
205+
blocks[1] = pindex->pprev;
206+
blocks[0] = blocks[1]->pprev;
207+
208+
// Sorting network.
209+
if (blocks[0]->nTime > blocks[2]->nTime) {
210+
std::swap(blocks[0], blocks[2]);
211+
}
212+
213+
if (blocks[0]->nTime > blocks[1]->nTime) {
214+
std::swap(blocks[0], blocks[1]);
215+
}
216+
217+
if (blocks[1]->nTime > blocks[2]->nTime) {
218+
std::swap(blocks[1], blocks[2]);
219+
}
220+
221+
// We should have our candidate in the middle now.
222+
return blocks[1];
223+
}
224+
225+
/**
226+
* Compute the next required proof of work using a weighted average of the
227+
* estimated hashrate per block.
228+
*
229+
* Using a weighted average ensure that the timestamp parameter cancels out in
230+
* most of the calculation - except for the timestamp of the first and last
231+
* block. Because timestamps are the least trustworthy information we have as
232+
* input, this ensures the algorithm is more resistant to malicious inputs.
233+
*/
234+
uint32_t GetNextCashWorkRequired(const CBlockIndex *pindexPrev,
235+
const CBlockHeader *pblock,
236+
const Consensus::Params &params) {
237+
// This cannot handle the genesis block and early blocks in general.
238+
assert(pindexPrev);
239+
240+
// Special difficulty rule for testnet:
241+
// If the new block's timestamp is more than 2* 10 minutes then allow
242+
// mining of a min-difficulty block.
243+
if (params.fPowAllowMinDifficultyBlocks &&
244+
(pblock->GetBlockTime() >
245+
pindexPrev->GetBlockTime() + 2 * params.nPowTargetSpacing)) {
246+
return UintToArith256(params.powLimit).GetCompact();
247+
}
248+
249+
// Compute the difficulty based on the full adjustement interval.
250+
const uint32_t nHeight = pindexPrev->nHeight;
251+
assert(nHeight >= params.DifficultyAdjustmentInterval());
252+
253+
// Get the last suitable block of the difficulty interval.
254+
const CBlockIndex *pindexLast = GetSuitableBlock(pindexPrev);
255+
assert(pindexLast);
256+
257+
// Get the first suitable block of the difficulty interval.
258+
uint32_t nHeightFirst = nHeight - 144;
259+
const CBlockIndex *pindexFirst =
260+
GetSuitableBlock(pindexPrev->GetAncestor(nHeightFirst));
261+
assert(pindexFirst);
262+
263+
// Compute the target based on time and work done during the interval.
264+
const arith_uint256 nextTarget =
265+
ComputeTarget(pindexFirst, pindexLast, params);
266+
267+
const arith_uint256 powLimit = UintToArith256(params.powLimit);
268+
if (nextTarget > powLimit) {
269+
return powLimit.GetCompact();
270+
}
271+
272+
return nextTarget.GetCompact();
273+
}

src/pow.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,11 @@ uint32_t CalculateNextWorkRequired(const CBlockIndex *pindexPrev,
2727
*/
2828
bool CheckProofOfWork(uint256 hash, uint32_t nBits, const Consensus::Params &);
2929

30+
/**
31+
* Bitcoin cash's difficulty adjustment mechanism.
32+
*/
33+
uint32_t GetNextCashWorkRequired(const CBlockIndex *pindexPrev,
34+
const CBlockHeader *pblock,
35+
const Consensus::Params &params);
36+
3037
#endif // BITCOIN_POW_H

src/test/pow_tests.cpp

Lines changed: 182 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test) {
8484
blocks[i].nTime = 1269211443 + i * params.nPowTargetSpacing;
8585
blocks[i].nBits = 0x207fffff; /* target 0x7fffff000... */
8686
blocks[i].nChainWork =
87-
i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i - 1])
87+
i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i])
8888
: arith_uint256(0);
8989
}
9090

@@ -106,6 +106,7 @@ static CBlockIndex GetBlockIndex(CBlockIndex *pindexPrev, int64_t nTimeInterval,
106106
block.nTime = pindexPrev->nTime + nTimeInterval;
107107
block.nBits = nBits;
108108

109+
block.nChainWork = pindexPrev->nChainWork + GetBlockProof(block);
109110
return block;
110111
}
111112

@@ -119,12 +120,14 @@ BOOST_AUTO_TEST_CASE(retargeting_test) {
119120
arith_uint256 currentPow = powLimit >> 1;
120121
uint32_t initialBits = currentPow.GetCompact();
121122

122-
// Genesis block?
123+
// Genesis block.
123124
blocks[0] = CBlockIndex();
124125
blocks[0].nHeight = 0;
125126
blocks[0].nTime = 1269211443;
126127
blocks[0].nBits = initialBits;
127128

129+
blocks[0].nChainWork = GetBlockProof(blocks[0]);
130+
128131
// Pile up some blocks.
129132
for (size_t i = 1; i < 100; i++) {
130133
blocks[i] = GetBlockIndex(&blocks[i - 1], params.nPowTargetSpacing,
@@ -187,4 +190,181 @@ BOOST_AUTO_TEST_CASE(retargeting_test) {
187190
powLimit.GetCompact());
188191
}
189192

193+
BOOST_AUTO_TEST_CASE(cash_difficulty_test) {
194+
SelectParams(CBaseChainParams::MAIN);
195+
const Consensus::Params &params = Params().GetConsensus();
196+
197+
std::vector<CBlockIndex> blocks(3000);
198+
199+
const arith_uint256 powLimit = UintToArith256(params.powLimit);
200+
uint32_t powLimitBits = powLimit.GetCompact();
201+
arith_uint256 currentPow = powLimit >> 4;
202+
uint32_t initialBits = currentPow.GetCompact();
203+
204+
// Genesis block.
205+
blocks[0] = CBlockIndex();
206+
blocks[0].nHeight = 0;
207+
blocks[0].nTime = 1269211443;
208+
blocks[0].nBits = initialBits;
209+
210+
blocks[0].nChainWork = GetBlockProof(blocks[0]);
211+
212+
// Block counter.
213+
size_t i;
214+
215+
// Pile up some blocks every 10 mins to establish some history.
216+
for (i = 1; i < 2050; i++) {
217+
blocks[i] = GetBlockIndex(&blocks[i - 1], 600, initialBits);
218+
}
219+
220+
CBlockHeader blkHeaderDummy;
221+
uint32_t nBits =
222+
GetNextCashWorkRequired(&blocks[2049], &blkHeaderDummy, params);
223+
224+
// Difficulty stays the same as long as we produce a block every 10 mins.
225+
for (size_t j = 0; j < 10; i++, j++) {
226+
blocks[i] = GetBlockIndex(&blocks[i - 1], 600, nBits);
227+
BOOST_CHECK_EQUAL(
228+
GetNextCashWorkRequired(&blocks[i], &blkHeaderDummy, params),
229+
nBits);
230+
}
231+
232+
// Make sure we skip over blocks that are out of wack. To do so, we produce
233+
// a block that is far in the future, and then produce a block with the
234+
// expected timestamp.
235+
blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits);
236+
BOOST_CHECK_EQUAL(
237+
GetNextCashWorkRequired(&blocks[i++], &blkHeaderDummy, params), nBits);
238+
blocks[i] = GetBlockIndex(&blocks[i - 1], 2 * 600 - 6000, nBits);
239+
BOOST_CHECK_EQUAL(
240+
GetNextCashWorkRequired(&blocks[i++], &blkHeaderDummy, params), nBits);
241+
242+
// The system should continue unaffected by the block with a bogous
243+
// timestamps.
244+
for (size_t j = 0; j < 20; i++, j++) {
245+
blocks[i] = GetBlockIndex(&blocks[i - 1], 600, nBits);
246+
BOOST_CHECK_EQUAL(
247+
GetNextCashWorkRequired(&blocks[i], &blkHeaderDummy, params),
248+
nBits);
249+
}
250+
251+
// We start emitting blocks slightly faster. The first block has no impact.
252+
blocks[i] = GetBlockIndex(&blocks[i - 1], 550, nBits);
253+
BOOST_CHECK_EQUAL(
254+
GetNextCashWorkRequired(&blocks[i++], &blkHeaderDummy, params), nBits);
255+
256+
// Now we should see difficulty increase slowly.
257+
for (size_t j = 0; j < 10; i++, j++) {
258+
blocks[i] = GetBlockIndex(&blocks[i - 1], 550, nBits);
259+
const uint32_t nextBits =
260+
GetNextCashWorkRequired(&blocks[i], &blkHeaderDummy, params);
261+
262+
arith_uint256 currentTarget;
263+
currentTarget.SetCompact(nBits);
264+
arith_uint256 nextTarget;
265+
nextTarget.SetCompact(nextBits);
266+
267+
// Make sure that difficulty increases very slowly.
268+
BOOST_CHECK(nextTarget < currentTarget);
269+
BOOST_CHECK((currentTarget - nextTarget) < (currentTarget >> 10));
270+
271+
nBits = nextBits;
272+
}
273+
274+
// Check the actual value.
275+
BOOST_CHECK_EQUAL(nBits, 0x1c0fe7b1);
276+
277+
// If we dramatically shorten block production, difficulty increases faster.
278+
for (size_t j = 0; j < 20; i++, j++) {
279+
blocks[i] = GetBlockIndex(&blocks[i - 1], 10, nBits);
280+
const uint32_t nextBits =
281+
GetNextCashWorkRequired(&blocks[i], &blkHeaderDummy, params);
282+
283+
arith_uint256 currentTarget;
284+
currentTarget.SetCompact(nBits);
285+
arith_uint256 nextTarget;
286+
nextTarget.SetCompact(nextBits);
287+
288+
// Make sure that difficulty increases faster.
289+
BOOST_CHECK(nextTarget < currentTarget);
290+
BOOST_CHECK((currentTarget - nextTarget) < (currentTarget >> 4));
291+
292+
nBits = nextBits;
293+
}
294+
295+
// Check the actual value.
296+
BOOST_CHECK_EQUAL(nBits, 0x1c0db19f);
297+
298+
// We start to emit blocks significantly slower. The first block has no
299+
// impact.
300+
blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits);
301+
nBits = GetNextCashWorkRequired(&blocks[i++], &blkHeaderDummy, params);
302+
303+
// Check the actual value.
304+
BOOST_CHECK_EQUAL(nBits, 0x1c0d9222);
305+
306+
// If we dramatically slow down block production, difficulty decreases.
307+
for (size_t j = 0; j < 93; i++, j++) {
308+
blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits);
309+
const uint32_t nextBits =
310+
GetNextCashWorkRequired(&blocks[i], &blkHeaderDummy, params);
311+
312+
arith_uint256 currentTarget;
313+
currentTarget.SetCompact(nBits);
314+
arith_uint256 nextTarget;
315+
nextTarget.SetCompact(nextBits);
316+
317+
// Check the difficulty decreases.
318+
BOOST_CHECK(nextTarget <= powLimit);
319+
BOOST_CHECK(nextTarget > currentTarget);
320+
BOOST_CHECK((nextTarget - currentTarget) < (currentTarget >> 3));
321+
322+
nBits = nextBits;
323+
}
324+
325+
// Check the actual value.
326+
BOOST_CHECK_EQUAL(nBits, 0x1c2f13b9);
327+
328+
// Due to the window of time being bounded, next block's difficulty actually
329+
// gets harder.
330+
blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits);
331+
nBits = GetNextCashWorkRequired(&blocks[i++], &blkHeaderDummy, params);
332+
BOOST_CHECK_EQUAL(nBits, 0x1c2ee9bf);
333+
334+
// And goes down again. It takes a while due to the window being bounded and
335+
// the skewed block causes 2 blocks to get out of the window.
336+
for (size_t j = 0; j < 192; i++, j++) {
337+
blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits);
338+
const uint32_t nextBits =
339+
GetNextCashWorkRequired(&blocks[i], &blkHeaderDummy, params);
340+
341+
arith_uint256 currentTarget;
342+
currentTarget.SetCompact(nBits);
343+
arith_uint256 nextTarget;
344+
nextTarget.SetCompact(nextBits);
345+
346+
// Check the difficulty decreases.
347+
BOOST_CHECK(nextTarget <= powLimit);
348+
BOOST_CHECK(nextTarget > currentTarget);
349+
BOOST_CHECK((nextTarget - currentTarget) < (currentTarget >> 3));
350+
351+
nBits = nextBits;
352+
}
353+
354+
// Check the actual value.
355+
BOOST_CHECK_EQUAL(nBits, 0x1d00ffff);
356+
357+
// Once the difficulty reached the minimum allowed level, it doesn't get any
358+
// easier.
359+
for (size_t j = 0; j < 5; i++, j++) {
360+
blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits);
361+
const uint32_t nextBits =
362+
GetNextCashWorkRequired(&blocks[i], &blkHeaderDummy, params);
363+
364+
// Check the difficulty stays constant.
365+
BOOST_CHECK_EQUAL(nextBits, powLimitBits);
366+
nBits = nextBits;
367+
}
368+
}
369+
190370
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)