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