Bitcoin ABC  0.22.13
P2P Digital Currency
aserti32d_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2020 The Bitcoin Core developers
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <pow/aserti32d.h>
6 
7 #include <chain.h>
8 #include <chainparams.h>
9 #include <config.h>
10 #include <consensus/activation.h>
11 #include <pow/pow.h>
12 
13 #include <test/util/setup_common.h>
14 
15 #include <boost/test/unit_test.hpp>
16 
17 #include <cmath>
18 
19 BOOST_FIXTURE_TEST_SUITE(aserti32d_tests, BasicTestingSetup)
20 
21 static CBlockIndex GetBlockIndex(CBlockIndex *pindexPrev, int64_t nTimeInterval,
22  uint32_t nBits) {
23  CBlockIndex block;
24  block.pprev = pindexPrev;
25  block.nHeight = pindexPrev->nHeight + 1;
26  block.nTime = pindexPrev->nTime + nTimeInterval;
27  block.nBits = nBits;
28 
29  block.BuildSkip();
30  block.nChainWork = pindexPrev->nChainWork + GetBlockProof(block);
31  return block;
32 }
33 
34 static double TargetFromBits(const uint32_t nBits) {
35  return (nBits & 0xff'ff'ff) * pow(256, (nBits >> 24) - 3);
36 }
37 
38 static double GetASERTApproximationError(const CBlockIndex *pindexPrev,
39  const uint32_t finalBits,
40  const CBlockIndex *pindexAnchorBlock) {
41  const int64_t nHeightDiff =
42  pindexPrev->nHeight - pindexAnchorBlock->nHeight;
43  const int64_t nTimeDiff =
44  pindexPrev->GetBlockTime() - pindexAnchorBlock->pprev->GetBlockTime();
45  const uint32_t initialBits = pindexAnchorBlock->nBits;
46 
47  BOOST_CHECK(nHeightDiff >= 0);
48  double dInitialPow = TargetFromBits(initialBits);
49  double dFinalPow = TargetFromBits(finalBits);
50 
51  double dExponent =
52  double(nTimeDiff - (nHeightDiff + 1) * 600) / double(2 * 24 * 3600);
53  double dTarget = dInitialPow * pow(2, dExponent);
54 
55  return (dFinalPow - dTarget) / dTarget;
56 }
57 
58 BOOST_AUTO_TEST_CASE(asert_difficulty_test) {
60 
61  std::vector<CBlockIndex> blocks(3000 + 2 * 24 * 3600);
62 
63  const Consensus::Params &params = config.GetChainParams().GetConsensus();
64  const arith_uint256 powLimit = UintToArith256(params.powLimit);
65  arith_uint256 currentPow = powLimit >> 3;
66  uint32_t initialBits = currentPow.GetCompact();
67  double dMaxErr = 0.0001166792656486;
68 
69  // Genesis block, and parent of ASERT anchor block in this test case.
70  blocks[0] = CBlockIndex();
71  blocks[0].nHeight = 0;
72  blocks[0].nTime = 1269211443;
73  // The pre-anchor block's nBits should never be used, so we set it to a
74  // nonsense value in order to trigger an error if it is ever accessed
75  blocks[0].nBits = 0x0dedbeef;
76 
77  blocks[0].nChainWork = GetBlockProof(blocks[0]);
78 
79  // Block counter.
80  size_t i = 1;
81 
82  // ASERT anchor block. We give this one a solvetime of 150 seconds to ensure
83  // that the solvetime between the pre-anchor and the anchor blocks is
84  // actually used.
85  blocks[1] = GetBlockIndex(&blocks[0], 150, initialBits);
86  // The nBits for the next block should not be equal to the anchor block's
87  // nBits
88  CBlockHeader blkHeaderDummy;
89  uint32_t nBits = GetNextASERTWorkRequired(&blocks[i++], &blkHeaderDummy,
90  params, &blocks[1]);
91  BOOST_CHECK(fabs(GetASERTApproximationError(&blocks[i - 1], nBits,
92  &blocks[1])) < dMaxErr);
93  BOOST_CHECK(nBits != initialBits);
94 
95  // If we add another block at 1050 seconds, we should return to the anchor
96  // block's nBits
97  blocks[i] = GetBlockIndex(&blocks[i - 1], 1050, nBits);
98  nBits = GetNextASERTWorkRequired(&blocks[i++], &blkHeaderDummy, params,
99  &blocks[1]);
100  BOOST_CHECK(nBits == initialBits);
101  BOOST_CHECK(fabs(GetASERTApproximationError(&blocks[i - 1], nBits,
102  &blocks[1])) < dMaxErr);
103 
104  currentPow = arith_uint256().SetCompact(nBits);
105  // Before we do anything else, check that timestamps *before* the anchor
106  // block work fine. Jumping 2 days into the past will give a timestamp
107  // before the achnor, and should halve the target
108  blocks[i] = GetBlockIndex(&blocks[i - 1], 600 - 172800, nBits);
109  nBits = GetNextASERTWorkRequired(&blocks[i++], &blkHeaderDummy, params,
110  &blocks[1]);
111  currentPow = arith_uint256().SetCompact(nBits);
112  // Because nBits truncates target, we don't end up with exactly 1/2 the
113  // target
114  BOOST_CHECK(currentPow <= arith_uint256().SetCompact(initialBits) / 2);
115  BOOST_CHECK(currentPow >= arith_uint256().SetCompact(initialBits - 1) / 2);
116  BOOST_CHECK(fabs(GetASERTApproximationError(&blocks[i - 1], nBits,
117  &blocks[1])) < dMaxErr);
118 
119  // Jumping forward 2 days should return the target to the initial value
120  blocks[i] = GetBlockIndex(&blocks[i - 1], 600 + 172800, nBits);
121  nBits = GetNextASERTWorkRequired(&blocks[i++], &blkHeaderDummy, params,
122  &blocks[1]);
123  currentPow = arith_uint256().SetCompact(nBits);
124  BOOST_CHECK(nBits == initialBits);
125  BOOST_CHECK(fabs(GetASERTApproximationError(&blocks[i - 1], nBits,
126  &blocks[1])) < dMaxErr);
127 
128  // Pile up some blocks every 10 mins to establish some history.
129  for (; i < 150; i++) {
130  blocks[i] = GetBlockIndex(&blocks[i - 1], 600, nBits);
131  BOOST_CHECK_EQUAL(blocks[i].nBits, nBits);
132  }
133 
134  nBits = GetNextASERTWorkRequired(&blocks[i - 1], &blkHeaderDummy, params,
135  &blocks[1]);
136 
137  BOOST_CHECK_EQUAL(nBits, initialBits);
138 
139  // Difficulty stays the same as long as we produce a block every 10 mins.
140  for (size_t j = 0; j < 10; i++, j++) {
141  blocks[i] = GetBlockIndex(&blocks[i - 1], 600, nBits);
142  BOOST_CHECK_EQUAL(GetNextASERTWorkRequired(&blocks[i], &blkHeaderDummy,
143  params, &blocks[1]),
144  nBits);
145  }
146 
147  // If we add a two blocks whose solvetimes together add up to 1200s,
148  // then the next block's target should be the same as the one before these
149  // blocks (at this point, equal to initialBits).
150  blocks[i] = GetBlockIndex(&blocks[i - 1], 300, nBits);
151  nBits = GetNextASERTWorkRequired(&blocks[i++], &blkHeaderDummy, params,
152  &blocks[1]);
153  BOOST_CHECK(fabs(GetASERTApproximationError(&blocks[i - 1], nBits,
154  &blocks[1])) < dMaxErr);
155  // relative
156  BOOST_CHECK(fabs(GetASERTApproximationError(&blocks[i - 1], nBits,
157  &blocks[i - 2])) < dMaxErr);
158  blocks[i] = GetBlockIndex(&blocks[i - 1], 900, nBits);
159  nBits = GetNextASERTWorkRequired(&blocks[i++], &blkHeaderDummy, params,
160  &blocks[1]);
161  // absolute
162  BOOST_CHECK(fabs(GetASERTApproximationError(&blocks[i - 1], nBits,
163  &blocks[1])) < dMaxErr);
164  // relative
165  BOOST_CHECK(fabs(GetASERTApproximationError(&blocks[i - 1], nBits,
166  &blocks[i - 2])) < dMaxErr);
167  BOOST_CHECK_EQUAL(nBits, initialBits);
168  BOOST_CHECK(nBits != blocks[i - 1].nBits);
169 
170  // Same in reverse - this time slower block first, followed by faster block.
171  blocks[i] = GetBlockIndex(&blocks[i - 1], 900, nBits);
172  nBits = GetNextASERTWorkRequired(&blocks[i++], &blkHeaderDummy, params,
173  &blocks[1]);
174  // absolute
175  BOOST_CHECK(fabs(GetASERTApproximationError(&blocks[i - 1], nBits,
176  &blocks[1])) < dMaxErr);
177  // relative
178  BOOST_CHECK(fabs(GetASERTApproximationError(&blocks[i - 1], nBits,
179  &blocks[i - 2])) < dMaxErr);
180  blocks[i] = GetBlockIndex(&blocks[i - 1], 300, nBits);
181  nBits = GetNextASERTWorkRequired(&blocks[i++], &blkHeaderDummy, params,
182  &blocks[1]);
183  // absolute
184  BOOST_CHECK(fabs(GetASERTApproximationError(&blocks[i - 1], nBits,
185  &blocks[1])) < dMaxErr);
186  // relative
187  BOOST_CHECK(fabs(GetASERTApproximationError(&blocks[i - 1], nBits,
188  &blocks[i - 2])) < dMaxErr);
189  BOOST_CHECK_EQUAL(nBits, initialBits);
190  BOOST_CHECK(nBits != blocks[i - 1].nBits);
191 
192  // Jumping forward 2 days should double the target (halve the difficulty)
193  blocks[i] = GetBlockIndex(&blocks[i - 1], 600 + 2 * 24 * 3600, nBits);
194  nBits = GetNextASERTWorkRequired(&blocks[i++], &blkHeaderDummy, params,
195  &blocks[1]);
196  // absolute
197  BOOST_CHECK(fabs(GetASERTApproximationError(&blocks[i - 1], nBits,
198  &blocks[1])) < dMaxErr);
199  // relative
200  BOOST_CHECK(fabs(GetASERTApproximationError(&blocks[i - 1], nBits,
201  &blocks[i - 2])) < dMaxErr);
202  currentPow = arith_uint256().SetCompact(nBits) / 2;
203  BOOST_CHECK_EQUAL(currentPow.GetCompact(), initialBits);
204 
205  // Jumping backward 2 days should bring target back to where we started
206  blocks[i] = GetBlockIndex(&blocks[i - 1], 600 - 2 * 24 * 3600, nBits);
207  nBits = GetNextASERTWorkRequired(&blocks[i++], &blkHeaderDummy, params,
208  &blocks[1]);
210  &blocks[i - 1], nBits, &blocks[1])) < dMaxErr); // absolute
211  BOOST_CHECK(fabs(GetASERTApproximationError(&blocks[i - 1], nBits,
212  &blocks[i - 2])) <
213  dMaxErr); // relative
214  BOOST_CHECK_EQUAL(nBits, initialBits);
215 
216  // Jumping backward 2 days should halve the target (double the difficulty)
217  blocks[i] = GetBlockIndex(&blocks[i - 1], 600 - 2 * 24 * 3600, nBits);
218  nBits = GetNextASERTWorkRequired(&blocks[i++], &blkHeaderDummy, params,
219  &blocks[1]);
220  // absolute
221  BOOST_CHECK(fabs(GetASERTApproximationError(&blocks[i - 1], nBits,
222  &blocks[1])) < dMaxErr);
223  // relative
224  BOOST_CHECK(fabs(GetASERTApproximationError(&blocks[i - 1], nBits,
225  &blocks[i - 2])) < dMaxErr);
226  currentPow = arith_uint256().SetCompact(nBits);
227  // Because nBits truncates target, we don't end up with exactly 1/2 the
228  // target
229  BOOST_CHECK(currentPow <= arith_uint256().SetCompact(initialBits) / 2);
230  BOOST_CHECK(currentPow >= arith_uint256().SetCompact(initialBits - 1) / 2);
231 
232  // And forward again
233  blocks[i] = GetBlockIndex(&blocks[i - 1], 600 + 2 * 24 * 3600, nBits);
234  nBits = GetNextASERTWorkRequired(&blocks[i++], &blkHeaderDummy, params,
235  &blocks[1]);
236  // absolute
237  BOOST_CHECK(fabs(GetASERTApproximationError(&blocks[i - 1], nBits,
238  &blocks[1])) < dMaxErr);
239  // relative
240  BOOST_CHECK(fabs(GetASERTApproximationError(&blocks[i - 1], nBits,
241  &blocks[i - 2])) < dMaxErr);
242  BOOST_CHECK_EQUAL(nBits, initialBits);
243  blocks[i] = GetBlockIndex(&blocks[i - 1], 600 + 2 * 24 * 3600, nBits);
244  nBits = GetNextASERTWorkRequired(&blocks[i++], &blkHeaderDummy, params,
245  &blocks[1]);
246  // absolute
247  BOOST_CHECK(fabs(GetASERTApproximationError(&blocks[i - 1], nBits,
248  &blocks[1])) < dMaxErr);
249  // relative
250  BOOST_CHECK(fabs(GetASERTApproximationError(&blocks[i - 1], nBits,
251  &blocks[i - 2])) < dMaxErr);
252  currentPow = arith_uint256().SetCompact(nBits) / 2;
253  BOOST_CHECK_EQUAL(currentPow.GetCompact(), initialBits);
254 
255  // Iterate over the entire -2*24*3600..+2*24*3600 range to check that our
256  // integer approximation:
257  // 1. Should be monotonic.
258  // 2. Should change target at least once every 8 seconds (worst-case:
259  // 15-bit precision on nBits)
260  // 3. Should never change target by more than XXXX per 1-second step.
261  // 4. Never exceeds dMaxError in absolute error vs a double float
262  // calculation.
263  // 5. Has almost exactly the dMax and dMin errors we expect for the
264  // formula.
265  double dMin = 0;
266  double dMax = 0;
267  double dErr;
268  double dRelMin = 0;
269  double dRelMax = 0;
270  double dRelErr;
271  double dMaxStep = 0;
272  uint32_t nBitsRingBuffer[8];
273  double dStep = 0;
274  blocks[i] = GetBlockIndex(&blocks[i - 1], -2 * 24 * 3600 - 30, nBits);
275  for (size_t j = 0; j < 4 * 24 * 3600 + 660; j++) {
276  blocks[i].nTime++;
277  nBits = GetNextASERTWorkRequired(&blocks[i], &blkHeaderDummy, params,
278  &blocks[1]);
279 
280  if (j > 8) {
281  // 1: Monotonic
282  BOOST_CHECK(
283  arith_uint256().SetCompact(nBits) >=
284  arith_uint256().SetCompact(nBitsRingBuffer[(j - 1) % 8]));
285  // 2: Changes at least once every 8 seconds (worst case: nBits =
286  // 1d008000 to 1d008001)
287  BOOST_CHECK(arith_uint256().SetCompact(nBits) >
288  arith_uint256().SetCompact(nBitsRingBuffer[j % 8]));
289  // 3: Check 1-sec step size
290  dStep = (TargetFromBits(nBits) -
291  TargetFromBits(nBitsRingBuffer[(j - 1) % 8])) /
292  TargetFromBits(nBits);
293  dMaxStep = std::max(dMaxStep, dStep);
294  // from nBits = 1d008000 to 1d008001
295  BOOST_CHECK(dStep < 0.0000314812106363);
296  }
297  nBitsRingBuffer[j % 8] = nBits;
298 
299  // 4 and 5: check error vs double precision float calculation
300  dErr = GetASERTApproximationError(&blocks[i], nBits, &blocks[1]);
301  dRelErr = GetASERTApproximationError(&blocks[i], nBits, &blocks[i - 1]);
302  dMin = std::min(dMin, dErr);
303  dMax = std::max(dMax, dErr);
304  dRelMin = std::min(dRelMin, dRelErr);
305  dRelMax = std::max(dRelMax, dRelErr);
306  BOOST_CHECK_MESSAGE(
307  fabs(dErr) < dMaxErr,
308  strprintf(
309  "solveTime: %d\tStep size: %.8f%%\tdErr: %.8f%%\tnBits: %0x\n",
310  int64_t(blocks[i].nTime) - blocks[i - 1].nTime, dStep * 100,
311  dErr * 100, nBits));
312  BOOST_CHECK_MESSAGE(
313  fabs(dRelErr) < dMaxErr,
314  strprintf("solveTime: %d\tStep size: %.8f%%\tdRelErr: "
315  "%.8f%%\tnBits: %0x\n",
316  int64_t(blocks[i].nTime) - blocks[i - 1].nTime,
317  dStep * 100, dRelErr * 100, nBits));
318  }
319  auto failMsg = strprintf(
320  "Min error: %16.14f%%\tMax error: %16.14f%%\tMax step: %16.14f%%\n",
321  dMin * 100, dMax * 100, dMaxStep * 100);
322  BOOST_CHECK_MESSAGE(
323  dMin < -0.0001013168981059 && dMin > -0.0001013168981060 &&
324  dMax > 0.0001166792656485 && dMax < 0.0001166792656486,
325  failMsg);
326  failMsg = strprintf("Min relError: %16.14f%%\tMax relError: %16.14f%%\n",
327  dRelMin * 100, dRelMax * 100);
328  BOOST_CHECK_MESSAGE(
329  dRelMin < -0.0001013168981059 && dRelMin > -0.0001013168981060 &&
330  dRelMax > 0.0001166792656485 && dRelMax < 0.0001166792656486,
331  failMsg);
332 
333  // Difficulty increases as long as we produce fast blocks
334  for (size_t j = 0; j < 100; i++, j++) {
335  uint32_t nextBits;
336  arith_uint256 currentTarget;
337  currentTarget.SetCompact(nBits);
338 
339  blocks[i] = GetBlockIndex(&blocks[i - 1], 500, nBits);
340  nextBits = GetNextASERTWorkRequired(&blocks[i], &blkHeaderDummy, params,
341  &blocks[1]);
342  arith_uint256 nextTarget;
343  nextTarget.SetCompact(nextBits);
344 
345  // Make sure that target is decreased
346  BOOST_CHECK(nextTarget <= currentTarget);
347 
348  nBits = nextBits;
349  }
350 }
351 
352 static std::string StrPrintCalcArgs(const arith_uint256 refTarget,
353  const int64_t targetSpacing,
354  const int64_t timeDiff,
355  const int64_t heightDiff,
356  const arith_uint256 expectedTarget,
357  const uint32_t expectednBits) {
358  return strprintf("\n"
359  "ref= %s\n"
360  "spacing= %d\n"
361  "timeDiff= %d\n"
362  "heightDiff= %d\n"
363  "expTarget= %s\n"
364  "exp nBits= 0x%08x\n",
365  refTarget.ToString(), targetSpacing, timeDiff, heightDiff,
366  expectedTarget.ToString(), expectednBits);
367 }
368 
369 // Tests of the CalculateASERT function.
370 BOOST_AUTO_TEST_CASE(calculate_asert_test) {
372  const Consensus::Params &params = config.GetChainParams().GetConsensus();
373  const int64_t nHalfLife = params.nDAAHalfLife;
374 
375  const arith_uint256 powLimit = UintToArith256(params.powLimit);
376  arith_uint256 initialTarget = powLimit >> 4;
377  int64_t height = 0;
378 
379  // The CalculateASERT function uses the absolute ASERT formulation
380  // and adds +1 to the height difference that it receives.
381  // The time difference passed to it must factor in the difference
382  // to the *parent* of the reference block.
383  // We assume the parent is ideally spaced in time before the reference
384  // block.
385  static const int64_t parent_time_diff = 600;
386 
387  // Steady
388  arith_uint256 nextTarget = CalculateASERT(
389  initialTarget, params.nPowTargetSpacing,
390  parent_time_diff + 600 /* nTimeDiff */, ++height, powLimit, nHalfLife);
391  BOOST_CHECK(nextTarget == initialTarget);
392 
393  // A block that arrives in half the expected time
394  nextTarget = CalculateASERT(initialTarget, params.nPowTargetSpacing,
395  parent_time_diff + 600 + 300, ++height,
396  powLimit, nHalfLife);
397  BOOST_CHECK(nextTarget < initialTarget);
398 
399  // A block that makes up for the shortfall of the previous one, restores the
400  // target to initial
401  arith_uint256 prevTarget = nextTarget;
402  nextTarget = CalculateASERT(initialTarget, params.nPowTargetSpacing,
403  parent_time_diff + 600 + 300 + 900, ++height,
404  powLimit, nHalfLife);
405  BOOST_CHECK(nextTarget > prevTarget);
406  BOOST_CHECK(nextTarget == initialTarget);
407 
408  // Two days ahead of schedule should double the target (halve the
409  // difficulty)
410  prevTarget = nextTarget;
411  nextTarget =
412  CalculateASERT(prevTarget, params.nPowTargetSpacing,
413  parent_time_diff + 288 * 1200, 288, powLimit, nHalfLife);
414  BOOST_CHECK(nextTarget == prevTarget * 2);
415 
416  // Two days behind schedule should halve the target (double the difficulty)
417  prevTarget = nextTarget;
418  nextTarget =
419  CalculateASERT(prevTarget, params.nPowTargetSpacing,
420  parent_time_diff + 288 * 0, 288, powLimit, nHalfLife);
421  BOOST_CHECK(nextTarget == prevTarget / 2);
422  BOOST_CHECK(nextTarget == initialTarget);
423 
424  // Ramp up from initialTarget to PowLimit - should only take 4 doublings...
425  uint32_t powLimit_nBits = powLimit.GetCompact();
426  uint32_t next_nBits;
427  for (size_t k = 0; k < 3; k++) {
428  prevTarget = nextTarget;
429  nextTarget = CalculateASERT(prevTarget, params.nPowTargetSpacing,
430  parent_time_diff + 288 * 1200, 288,
431  powLimit, nHalfLife);
432  BOOST_CHECK(nextTarget == prevTarget * 2);
433  BOOST_CHECK(nextTarget < powLimit);
434  next_nBits = nextTarget.GetCompact();
435  BOOST_CHECK(next_nBits != powLimit_nBits);
436  }
437 
438  prevTarget = nextTarget;
439  nextTarget =
440  CalculateASERT(prevTarget, params.nPowTargetSpacing,
441  parent_time_diff + 288 * 1200, 288, powLimit, nHalfLife);
442  next_nBits = nextTarget.GetCompact();
443  BOOST_CHECK(nextTarget == prevTarget * 2);
444  BOOST_CHECK(next_nBits == powLimit_nBits);
445 
446  // Fast periods now cannot increase target beyond POW limit, even if we try
447  // to overflow nextTarget. prevTarget is a uint256, so 256*2 = 512 days
448  // would overflow nextTarget unless CalculateASERT correctly detects this
449  // error
450  nextTarget = CalculateASERT(prevTarget, params.nPowTargetSpacing,
451  parent_time_diff + 512 * 144 * 600, 0, powLimit,
452  nHalfLife);
453  next_nBits = nextTarget.GetCompact();
454  BOOST_CHECK(next_nBits == powLimit_nBits);
455 
456  // We also need to watch for underflows on nextTarget. We need to withstand
457  // an extra ~446 days worth of blocks. This should bring down a powLimit
458  // target to the a minimum target of 1.
459  nextTarget = CalculateASERT(powLimit, params.nPowTargetSpacing, 0,
460  2 * (256 - 33) * 144, powLimit, nHalfLife);
461  next_nBits = nextTarget.GetCompact();
462  BOOST_CHECK_EQUAL(next_nBits, arith_uint256(1).GetCompact());
463 
464  // Define a structure holding parameters to pass to CalculateASERT.
465  // We are going to check some expected results against a vector of
466  // possible arguments.
467  struct calc_params {
468  arith_uint256 refTarget;
469  int64_t targetSpacing;
470  int64_t timeDiff;
471  int64_t heightDiff;
472  arith_uint256 expectedTarget;
473  uint32_t expectednBits;
474  };
475 
476  // Define some named input argument values
477  const arith_uint256 SINGLE_300_TARGET{
478  "00000000ffb1ffffffffffffffffffffffffffffffffffffffffffffffffffff"};
479  const arith_uint256 FUNNY_REF_TARGET{
480  "000000008000000000000000000fffffffffffffffffffffffffffffffffffff"};
481 
482  // Define our expected input and output values.
483  // The timeDiff entries exclude the `parent_time_diff` - this is
484  // added in the call to CalculateASERT in the test loop.
485  const std::vector<calc_params> calculate_args = {
486 
487  /* refTarget, targetSpacing, timeDiff, heightDiff, expectedTarget,
488  expectednBits */
489 
490  {powLimit, 600, 0, 2 * 144, powLimit >> 1, 0x1c7fffff},
491  {powLimit, 600, 0, 4 * 144, powLimit >> 2, 0x1c3fffff},
492  {powLimit >> 1, 600, 0, 2 * 144, powLimit >> 2, 0x1c3fffff},
493  {powLimit >> 2, 600, 0, 2 * 144, powLimit >> 3, 0x1c1fffff},
494  {powLimit >> 3, 600, 0, 2 * 144, powLimit >> 4, 0x1c0fffff},
495  {powLimit, 600, 0, 2 * (256 - 34) * 144, 3, 0x01030000},
496  {powLimit, 600, 0, 2 * (256 - 34) * 144 + 119, 3, 0x01030000},
497  {powLimit, 600, 0, 2 * (256 - 34) * 144 + 120, 2, 0x01020000},
498  {powLimit, 600, 0, 2 * (256 - 33) * 144 - 1, 2, 0x01020000},
499  // 1 bit less since we do not need to shift to 0
500  {powLimit, 600, 0, 2 * (256 - 33) * 144, 1, 0x01010000},
501  // more will not decrease below 1
502  {powLimit, 600, 0, 2 * (256 - 32) * 144, 1, 0x01010000},
503  {1, 600, 0, 2 * (256 - 32) * 144, 1, 0x01010000},
504  {powLimit, 600, 2 * (512 - 32) * 144, 0, powLimit, powLimit_nBits},
505  {1, 600, (512 - 64) * 144 * 600, 0, powLimit, powLimit_nBits},
506  // clamps to powLimit
507  {powLimit, 600, 300, 1, SINGLE_300_TARGET, 0x1d00ffb1},
508  // confuses any attempt to detect overflow by inspecting result
509  {FUNNY_REF_TARGET, 600, 600 * 2 * 33 * 144, 0, powLimit,
510  powLimit_nBits},
511  // overflow to exactly 2^256
512  {1, 600, 600 * 2 * 256 * 144, 0, powLimit, powLimit_nBits},
513  // just under powlimit (not clamped) yet over powlimit_nbits
514  {1, 600, 600 * 2 * 224 * 144 - 1, 0, arith_uint256(0xffff8) << 204,
515  powLimit_nBits},
516  };
517 
518  for (auto &v : calculate_args) {
519  nextTarget = CalculateASERT(v.refTarget, v.targetSpacing,
520  parent_time_diff + v.timeDiff, v.heightDiff,
521  powLimit, nHalfLife);
522  next_nBits = nextTarget.GetCompact();
523  const auto failMsg =
524  StrPrintCalcArgs(v.refTarget, v.targetSpacing,
525  parent_time_diff + v.timeDiff, v.heightDiff,
526  v.expectedTarget, v.expectednBits) +
527  strprintf("nextTarget= %s\nnext nBits= 0x%08x\n",
528  nextTarget.ToString(), next_nBits);
529  BOOST_CHECK_MESSAGE(nextTarget == v.expectedTarget &&
530  next_nBits == v.expectednBits,
531  failMsg);
532  }
533 }
534 
536 public:
537  ChainParamsWithDAAActivation(const CChainParams &chainParams, int daaHeight)
538  : CChainParams(chainParams) {
539  consensus.daaHeight = daaHeight;
540  }
541 };
542 
547 BOOST_AUTO_TEST_CASE(asert_activation_anchor_test) {
548  // Make a custom chain params based on mainnet, activating the cw144 DAA
549  // at a lower height than usual, so we don't need to waste time making a
550  // 504000-long chain.
551  const auto mainChainParams = CreateChainParams(CBaseChainParams::MAIN);
552  const ChainParamsWithDAAActivation chainParams(*mainChainParams, 2016);
553  const Consensus::Params &params = chainParams.GetConsensus();
554 
555  const int64_t activationTime =
556  gArgs.GetArg("-axionactivationtime", params.axionActivationTime);
557  CBlockHeader blkHeaderDummy;
558 
559  // an arbitrary compact target for our chain (based on BCH chain ~ Aug 10
560  // 2020).
561  uint32_t initialBits = 0x1802a842;
562 
563  // Block store for anonymous blocks; needs to be big enough to fit all
564  // generated blocks in this test.
565  std::vector<CBlockIndex> blocks(10000);
566  int bidx = 1;
567 
568  // Genesis block.
569  blocks[0].nHeight = 0;
570  blocks[0].nTime = 1269211443;
571  blocks[0].nBits = initialBits;
572  blocks[0].nChainWork = GetBlockProof(blocks[0]);
573 
574  // Pile up a random number of blocks to establish some history of random
575  // height. cw144 DAA requires us to have height at least 2016, dunno why
576  // that much.
577  const int initialBlockCount = 2000 + int(InsecureRandRange(1000));
578  for (int i = 1; i < initialBlockCount; i++) {
579  blocks[bidx] = GetBlockIndex(&blocks[bidx - 1], 600, initialBits);
580  bidx++;
581  BOOST_REQUIRE(bidx < int(blocks.size()));
582  }
583 
584  // Start making blocks prior to activation. First, make a block about 1 day
585  // before activation. Then put down 145 more blocks with 500 second
586  // solvetime each, such that the MTP on the final block is 1 second short of
587  // activationTime.
588  {
589  blocks[bidx] = GetBlockIndex(&blocks[bidx - 1], 600, initialBits);
590  blocks[bidx].nTime = activationTime - 140 * 500 - 1;
591  bidx++;
592  }
593  for (int i = 0; i < 145; i++) {
594  BOOST_REQUIRE(bidx < int(blocks.size()));
595  blocks[bidx] = GetBlockIndex(&blocks[bidx - 1], 500, initialBits);
596  bidx++;
597  }
598  CBlockIndex *pindexPreActivation = &blocks[bidx - 1];
599  BOOST_CHECK_EQUAL(pindexPreActivation->nTime, activationTime + 5 * 500 - 1);
600  BOOST_CHECK_EQUAL(pindexPreActivation->GetMedianTimePast(),
601  activationTime - 1);
602  BOOST_CHECK(IsDAAEnabled(params, pindexPreActivation));
603 
604  // If we consult DAA, then it uses cw144 which returns a significantly lower
605  // target because we have been mining too fast by a ratio 600/500 for a
606  // whole day.
607  BOOST_CHECK(!IsAxionEnabled(params, pindexPreActivation));
609  GetNextWorkRequired(pindexPreActivation, &blkHeaderDummy, chainParams),
610  0x180236e1);
611 
612  // ASERT has never run yet, so cache is unpopulated.
614 
621  // Create an activating block with expected solvetime, taking the cw144
622  // difficulty we just saw. Since solvetime is expected the next target is
623  // unchanged.
624  CBlockIndex indexActivation0 =
625  GetBlockIndex(pindexPreActivation, 600, 0x180236e1);
626  BOOST_CHECK(IsAxionEnabled(params, &indexActivation0));
628  GetNextWorkRequired(&indexActivation0, &blkHeaderDummy, chainParams),
629  0x180236e1);
630  // second call will have used anchor cache, shouldn't change anything
631  BOOST_CHECK_EQUAL(GetASERTAnchorBlockCache(), &indexActivation0);
633  GetNextWorkRequired(&indexActivation0, &blkHeaderDummy, chainParams),
634  0x180236e1);
635 
636  // Now we'll generate some more activations/anchors, using unique targets
637  // for each one (if the algo gets confused between different anchors, we
638  // will know).
639 
640  // Create an activating block with 0 solvetime, which will drop target by
641  // ~415/416.
642  CBlockIndex indexActivation1 =
643  GetBlockIndex(pindexPreActivation, 0, 0x18023456);
644  BOOST_CHECK(IsAxionEnabled(params, &indexActivation1));
645  // cache will be stale here, and we should get the right result regardless:
647  GetNextWorkRequired(&indexActivation1, &blkHeaderDummy, chainParams),
648  0x180232fd);
649  // second call will have used anchor cache, shouldn't change anything
650  BOOST_CHECK_EQUAL(GetASERTAnchorBlockCache(), &indexActivation1);
652  GetNextWorkRequired(&indexActivation1, &blkHeaderDummy, chainParams),
653  0x180232fd);
654  // for good measure, try again with wiped cache
657  GetNextWorkRequired(&indexActivation1, &blkHeaderDummy, chainParams),
658  0x180232fd);
659  BOOST_CHECK_EQUAL(GetASERTAnchorBlockCache(), &indexActivation1);
660 
661  // Try activation with expected solvetime, which will keep target the same.
662  uint32_t anchorBits2 = 0x180210fe;
663  CBlockIndex indexActivation2 =
664  GetBlockIndex(pindexPreActivation, 600, anchorBits2);
665  BOOST_CHECK(IsAxionEnabled(params, &indexActivation2));
667  GetNextWorkRequired(&indexActivation2, &blkHeaderDummy, chainParams),
668  anchorBits2);
669  BOOST_CHECK_EQUAL(GetASERTAnchorBlockCache(), &indexActivation2);
670 
671  // Try a three-month solvetime which will cause us to hit powLimit.
672  uint32_t anchorBits3 = 0x18034567;
673  CBlockIndex indexActivation3 =
674  GetBlockIndex(pindexPreActivation, 86400 * 90, anchorBits3);
675  BOOST_CHECK(IsAxionEnabled(params, &indexActivation2));
677  GetNextWorkRequired(&indexActivation3, &blkHeaderDummy, chainParams),
678  0x1d00ffff);
679  // If the next block jumps back in time, we get back our original difficulty
680  // level.
681  CBlockIndex indexActivation3_return =
682  GetBlockIndex(&indexActivation3, -86400 * 90 + 2 * 600, anchorBits3);
683  BOOST_CHECK_EQUAL(GetNextWorkRequired(&indexActivation3_return,
684  &blkHeaderDummy, chainParams),
685  anchorBits3);
686  // Retry for cache
687  BOOST_CHECK_EQUAL(GetNextWorkRequired(&indexActivation3_return,
688  &blkHeaderDummy, chainParams),
689  anchorBits3);
690  BOOST_CHECK_EQUAL(GetASERTAnchorBlockCache(), &indexActivation3);
691 
692  // Make an activation with MTP == activation exactly. This is a backwards
693  // timestamp jump so the resulting target is 1.2% lower.
694  CBlockIndex indexActivation4 =
695  GetBlockIndex(pindexPreActivation, 0, 0x18011111);
696  indexActivation4.nTime = activationTime;
697  BOOST_CHECK_EQUAL(indexActivation4.GetMedianTimePast(), activationTime);
698  BOOST_CHECK(IsAxionEnabled(params, &indexActivation4));
700  GetNextWorkRequired(&indexActivation4, &blkHeaderDummy, chainParams),
701  0x18010db3);
702  BOOST_CHECK_EQUAL(GetASERTAnchorBlockCache(), &indexActivation4);
703 
704  // Finally create a random chain on top of our second activation, using
705  // ASERT targets all the way. Erase cache so that this will do a fresh
706  // search for anchor at every step (fortauntely this is not too slow, due to
707  // the skiplist traversal)
708  CBlockIndex *pindexChain2 = &indexActivation2;
709  for (int i = 1; i < 1000; i++) {
710  BOOST_REQUIRE(bidx < int(blocks.size()));
712  uint32_t nextBits =
713  GetNextWorkRequired(pindexChain2, &blkHeaderDummy, chainParams);
714  BOOST_CHECK_EQUAL(GetASERTAnchorBlockCache(), &indexActivation2);
715  blocks[bidx] =
716  GetBlockIndex(pindexChain2, InsecureRandRange(1200), nextBits);
717  pindexChain2 = &blocks[bidx++];
718  }
719  // Scan back down to make sure all targets are same when we keep cached
720  // anchor.
721  for (CBlockIndex *pindex = pindexChain2; pindex != &indexActivation2;
722  pindex = pindex->pprev) {
723  uint32_t nextBits =
724  GetNextWorkRequired(pindex->pprev, &blkHeaderDummy, chainParams);
725  BOOST_CHECK_EQUAL(nextBits, pindex->nBits);
726  BOOST_CHECK_EQUAL(GetASERTAnchorBlockCache(), &indexActivation2);
727  }
728 }
729 
arith_uint256 nChainWork
(memory only) Total amount of work (expected number of hashes) in the chain up to and including this ...
Definition: blockindex.h:49
BOOST_AUTO_TEST_CASE(asert_difficulty_test)
std::string ToString() const
bool IsAxionEnabled(const Consensus::Params &params, const CBlockIndex *pindexPrev)
Check if November 15th, 2020 protocol upgrade has activated.
Definition: activation.cpp:78
int64_t GetBlockTime() const
Definition: blockindex.h:160
uint32_t GetNextASERTWorkRequired(const CBlockIndex *pindexPrev, const CBlockHeader *pblock, const Consensus::Params &params) noexcept
Definition: aserti32d.cpp:90
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition: blockindex.h:30
static std::string StrPrintCalcArgs(const arith_uint256 refTarget, const int64_t targetSpacing, const int64_t timeDiff, const int64_t heightDiff, const arith_uint256 expectedTarget, const uint32_t expectednBits)
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1201
arith_uint256 CalculateASERT(const arith_uint256 &refTarget, const int64_t nPowTargetSpacing, const int64_t nTimeDiff, const int64_t nHeightDiff, const arith_uint256 &powLimit, const int64_t nHalfLife) noexcept
Definition: aserti32d.cpp:164
ChainParamsWithDAAActivation(const CChainParams &chainParams, int daaHeight)
CChainParams defines various tweakable parameters of a given instance of the Bitcoin system...
Definition: chainparams.h:47
uint32_t nTime
Definition: blockindex.h:81
static bool IsDAAEnabled(const Consensus::Params &params, int nHeight)
Definition: activation.cpp:24
uint32_t GetCompact(bool fNegative=false) const
arith_uint256 UintToArith256(const uint256 &a)
static const std::string MAIN
BIP70 chain name strings (main, test or regtest)
uint256 powLimit
Proof of work parameters.
Definition: params.h:100
const CBlockIndex * GetASERTAnchorBlockCache() noexcept
Definition: aserti32d.cpp:19
std::unique_ptr< CChainParams > CreateChainParams(const std::string &chain)
Creates and returns a std::unique_ptr<CChainParams> of the chosen chain.
int64_t nPowTargetSpacing
Definition: params.h:104
int axionActivationTime
Unix time used for MTP activation of 15 Nov 2020 12:00:00 UTC upgrade.
Definition: params.h:84
void BuildSkip()
Build the skiplist pointer for this entry.
Definition: blockindex.cpp:76
Parameters that influence chain consensus.
Definition: params.h:59
256-bit unsigned big integer.
int64_t GetMedianTimePast() const
Definition: blockindex.h:172
uint32_t GetNextWorkRequired(const CBlockIndex *pindexPrev, const CBlockHeader *pblock, const CChainParams &chainParams)
Definition: pow.cpp:21
const CChainParams & GetChainParams() const override
Definition: config.h:61
static double TargetFromBits(const uint32_t nBits)
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
The block chain is a tree shaped structure starting with the genesis block at the root...
Definition: blockindex.h:23
void ResetASERTAnchorBlockCache() noexcept
ASERT caches a special block index for efficiency.
Definition: aserti32d.cpp:15
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: system.cpp:479
#define BOOST_AUTO_TEST_SUITE_END()
Definition: object.cpp:16
ArgsManager gArgs
Definition: system.cpp:76
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...
arith_uint256 GetBlockProof(const CBlockIndex &block)
Definition: chain.cpp:80
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: blockindex.h:36
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:59
static double GetASERTApproximationError(const CBlockIndex *pindexPrev, const uint32_t finalBits, const CBlockIndex *pindexAnchorBlock)
int64_t nDAAHalfLife
Definition: params.h:103
uint32_t nBits
Definition: blockindex.h:82
Nodes collect new transactions into a block, hash them into a hash tree, and scan through nonce value...
Definition: block.h:22
static CBlockIndex GetBlockIndex(CBlockIndex *pindexPrev, int64_t nTimeInterval, uint32_t nBits)
#define BOOST_CHECK(expr)
Definition: object.cpp:17