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